Token导航 LogoToken导航TokenDH.com
开发只读github未标认证来源可访问许可证需确认审计通过

react-render-performanceReact render 性能

Agent Skill

用于辅助前端页面、组件、样式和交互逻辑的开发与维护。它适合让 Agent 生成或审查 React、Next.js、Vue、Tailwind、CSS 等相关代码,整理组件结构,或定位布局和性能问题。使用时需要结合项目现有设计系统、路由和构建方式,避免只生成孤立片段;涉及页面改动时,应配合本地预览和构建检查确认视觉效果。

总安装

672

周安装

28

GitHub Stars

2

下载量

224
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:react-render-performance(React render 性能)
来源仓库:https://github.com/jonmumm/skills
仓库路径:skills/react-render-performance
安装命令:
npx skills add https://github.com/jonmumm/skills --skill react-render-performance
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/jonmumm/skills --skill react-render-performance

简介

专注 React 组件渲染速度提升,通过算法优化与 DOM 操作精简达成流畅体验。

  • 适用于列表滚动卡顿、动画掉帧或大数据量展示时的响应迟缓问题。
  • 可建议虚拟滚动、分片渲染及 requestIdleCallback 等延迟处理技术。
  • 需区分 CPU 密集型与 IO 密集型任务,采取差异化的优化策略组合。
  • 在低端设备上重点测试极端情况下的表现,确保普惠用户体验达标。

SKILL.md

React Render Performance

Patterns for minimizing unnecessary React re-renders when consuming external state. Prefer selector-based subscriptions over useState(wholeObject) — subscribe only to the slice each component needs.

Core idea

Storing a full state object in React state (e.g. useState(snapshot) and subscribing to every change) forces re-renders on any update. A component that only needs phase will still re-render when quiz.selectedWrong changes if both live in the same object.

Avoid: subscribe → setState(fullObject) → read a field in render. Prefer: subscribe to a selector or slice so the component re-renders only when that value changes. Every library below supports this; use it.

Tree position matters. The higher a component is in the tree, the more expensive a re-render becomes, because React re-renders it and all descendants. Subscribing to the whole store in App.tsx is especially bad — every store change re-renders the entire app. Push subscriptions down to the leaf or route-level components that actually need the data, or use selectors so high-level components only re-render when their slice changes.


Library patterns

XState (actors) — @xstate/react

Use useSelector(actor, selector) so the component re-renders only when the selected value changes.

// GOOD: stable selector — re-renders only when phase changes
import { useSelector } from "@xstate/react";
import { selectPhase } from "./selectors";

function PhaseIndicator({ actor }) {
  const phase = useSelector(actor, selectPhase);
  return <Text>{phase}</Text>;
}
// BAD: full snapshot in React state — re-renders on every actor change
const [snapshot, setSnapshot] = useState(null);
useEffect(() => {
  const sub = actor.subscribe((snap) => setSnapshot(snap));
  return () => sub.unsubscribe();
}, [actor]);
const phase = snapshot?.value?.sessionFlow; // unnecessary re-renders

Actor + ref for callbacks: Keep the actor in useState (so useSelector re-subscribes if the actor is replaced) and in a useRef for synchronous access in event handlers:

const [actor, setActor] = useState(() => {
  const a = createActor(machine);
  a.start();
  return a;
});
const actorRef = useRef(actor);
actorRef.current = actor;

function send(event) {
  actorRef.current.send(event);
}

@xstate/store — @xstate/store-react

Use useSelector(store, selector) to subscribe to a slice of store context. Re-renders only when the selected value changes (strict equality by default; optional custom compare).

// GOOD: select one field — re-renders only when count changes
import { createStore, useSelector } from "@xstate/store-react";

const store = createStore({
  context: { count: 0, name: "" },
  on: { inc: (ctx) => ({ ...ctx, count: ctx.count + 1 }) },
});

function CountDisplay() {
  const count = useSelector(store, (state) => state.context.count);
  return <span>{count}</span>;
}
// BAD: selecting whole context — re-renders on any context change
const context = useSelector(store, (state) => state.context);
return <span>{context.count}</span>;

Custom comparison when the selector returns an object:

const user = useSelector(
  store,
  (state) => state.context.user,
  (prev, next) => prev.id === next.id
);

Zustand

Use the store with a selector as the first argument. The component re-renders only when the selected value changes (referential equality).

// GOOD: selector — re-renders only when count changes
const count = useStore((state) => state.count);

// GOOD: primitive or stable ref — minimal re-renders
const phase = useStore((state) => state.session.phase);
// BAD: no selector — re-renders on every store change
const state = useStore();
return <span>{state.count}</span>;
// BAD: selecting a new object every time — re-renders every time
const { count, name } = useStore((state) => ({ count: state.count, name: state.name }));
// Use two selectors or useShallow instead

Use a module-level selector so the function reference is stable (see Selector rules below). For multiple fields, use useShallow or pick primitives:

import { useShallow } from "zustand/react/shallow";
const { count, name } = useStore(useShallow((state) => ({ count: state.count, name: state.name })));

Redux — react-redux

Use useSelector(selector) and select the smallest slice needed. Redux uses referential equality; selecting a new object every time forces re-renders.

// GOOD: select a primitive or stable reference
const phase = useSelector((state) => state.session.phase);
const count = useSelector((state) => state.counter);
// BAD: selecting whole slice — new object ref when any part of session updates
const session = useSelector((state) => state.session);
return <span>{session.phase}</span>;

For object slices use shallowEqual or a memoized selector:

import { shallowEqual, useSelector } from "react-redux";

const { phase, step } = useSelector(
  (state) => ({ phase: state.session.phase, step: state.session.step }),
  shallowEqual
);

Nanostores — @nanostores/react

Nanostores doesn’t take a selector in the hook; shape your stores so each consumer subscribes to a small store. Use computed stores to derive slices, or split state into multiple atoms.

// GOOD: one atom per logical slice, or computed for a derived slice
import { atom, computed } from "nanostores";
import { useStore } from "@nanostores/react";

const $session = atom({ phase: "idle", step: 0 });
const $phase = computed($session, (s) => s.phase);

function PhaseIndicator() {
  const phase = useStore($phase); // re-renders only when phase changes
  return <Text>{phase}</Text>;
}
// BAD: one big store, useStore on the whole thing — re-renders on any change
const $app = atom({ session: {...}, quiz: {...}, ui: {...} });
function PhaseIndicator() {
  const app = useStore($app);
  return <Text>{app.session.phase}</Text>;
}

Use map or atoms for granular updates and computed for derived values; then each component useStores only the store it needs.


React context

Context re-renders all consumers when the value reference changes. Prefer splitting by update frequency or exposing a subscribable store and selecting in the consumer.

// GOOD: split by update frequency
<FrequentContext.Provider value={frequentData}>
  <RareContext.Provider value={rareData}>
    {children}
  </RareContext.Provider>
</RareContext.Provider>
// GOOD: store in context, select in consumer (e.g. Zustand store, XState actor)
function useSessionPhase() {
  const store = useContext(StoreContext);
  return useSelector(store, (s) => s.phase);
}
// BAD: one context with everything — any change re-renders all consumers
<AppContext.Provider value={{ user, session, theme, settings, ... }}>

useSyncExternalStore (custom stores)

For stores that aren’t one of the above, use React’s useSyncExternalStore and subscribe to a slice in getSnapshot so the component only re-renders when that slice changes.

// GOOD: getSnapshot returns only the slice this component needs
const phase = useSyncExternalStore(
  store.subscribe,
  () => store.getSnapshot().session.phase,
  () => store.getSnapshot().session.phase
);
// BAD: getSnapshot returns full state — re-renders on every store change
const state = useSyncExternalStore(store.subscribe, store.getSnapshot, store.getSnapshot);
return <span>{state.session.phase}</span>;

Selector rules

  1. Keep selectors at module level — not inline in the component. Inline arrow functions create new references each render and can defeat equality checks.
// GOOD
const selectPhase = (snap) => snap.value?.sessionFlow;
function MyComponent({ actor }) {
  const phase = useSelector(actor, selectPhase);
}

// BAD — new function ref every render
function MyComponent({ actor }) {
  const phase = useSelector(actor, (snap) => snap.value?.sessionFlow);
}
  1. Return primitives or stable references. If the selector returns a new object/array every time, the component will re-render on every update. Prefer primitives or use a custom comparison when you must return an object.
  2. Don’t put expensive derivation in selectors. Heavy work belongs in useMemo in the component, not in the selector (selectors run often).

Anti-patterns

Anti-patternWhy it's badFix
setState(fullSnapshot) in subscribeEvery store/actor change re-rendersUse selector / slice (useSelector, selector arg, computed store)
No selector / whole store in hookSame as abovePass selector to useStore/useSelector; or use computed/small stores
Inline selector functionNew reference each renderModule-level selector
Selector returns new object every timeAlways re-rendersReturn primitive or use shallowEqual/custom compare
Mega-context with everythingAny update re-renders all consumersSplit context or put a store in context and select in consumer

When to use selectors

Use a selector / slice when:

  • The component needs 1–2 fields from a larger state
  • Different fields update at different rates (e.g. phase rarely, quiz state often)
  • Several components each need different parts of the same store
  • The component is high in the tree (e.g. App.tsx, layout, root route) — re-renders there cascade down the whole tree, so avoid subscribing to the whole store at that level

A single subscription is OK when:

  • The component needs most or all of the state
  • Updates are rare (e.g. user profile)
  • There’s only one consumer or it’s a leaf with no children

Rule of thumb: If a component re-renders more often than its visible output changes, add a selector (or a computed/small store). Use React DevTools Profiler to confirm.

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

34.65%
按下载量换算78

Claude

29.66%
按下载量换算66

Cursor

20.3%
按下载量换算45

Gemini CLI

9.48%
按下载量换算21

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

只读

该 Skill 主要提供规则、说明或参考内容,本身偏只读;真正读写文件、联网或执行命令仍取决于宿主 Agent 的任务。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills