关于 react-core
面向 React 开发者的基础参考 Skill,也为依赖 React 基础的生态 Skill 提供入门基准。内容涵盖组件、状态、渲染与表单等常见模式。
主要功能
- 01组件、JSX、属性与状态
- 02核心 Hook 及其用法
- 03组合模式与自定义 Hook
- 04条件渲染与列表渲染
- 05受控表单输入
- 06常见误用与规避建议
适用场景
- 01构建组件并传递数据
- 02为任务选择合适的核心 Hook
- 03渲染条件界面和列表
- 04实现由状态驱动的表单输入
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ bobmatnyc/ claude-mpm-skills --skill react-core安装后在 Claude Code 中输入/react-core确认已加载。
附带文件metadata.json
详细介绍
React 核心基础
概述
这是 React 通用基础知识的权威参考。本技能涵盖每个 React 应用共有的构建模块:组件和 JSX、属性和状态、核心 Hooks、组合模式、条件渲染和列表渲染,以及受控输入。它是生态系统技能(样式、数据获取、状态管理、部署)的基础“依赖 React”目标,这些技能都默认你了解 React 核心知识。
请将本技能聚焦于基础知识。高级 Hook 组合(由 SWR 支持的自定义 Hook、防抖上下文、记忆化 Provider)请使用同级的 react-hooks-composition 技能。对于复杂 UI 流程的显式有限状态机建模,请使用同级的 react-state-machine 技能。
何时使用本技能
在以下情况下使用本技能:
- 构建组件、连接属性或管理本地状态
- 根据具体问题选择合适的核心 Hook
- 渲染列表或条件 UI
- 实现受控表单输入
- 为依赖 React 生态系统技能建立基础
组件和 JSX
React 组件是一个返回 JSX 的函数。组件名称使用 PascalCase。返回单个根节点,或使用片段(<>...</>)包裹多个同级元素。
type GreetingProps = {
name: string;
};
function Greeting({ name }: GreetingProps) {
return (
<>
<h1>Hello, {name}</h1>
<p>Welcome back.</p>
</>
);
}
JSX 使用 {} 嵌入表达式。属性使用驼峰命名法(className、onClick、htmlFor)。JSX 返回 UI 描述;React 会将其与 DOM 协调。
属性和状态
属性将数据从父组件传递给子组件,在子组件中只读。状态保存组件自身拥有并会随时间变化的数据。
import { useState } from 'react';
function Counter({ step = 1 }: { step?: number }) {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount((prev) => prev + step)}>
Count: {count}
</button>
);
}
将属性和状态视为不可变数据。通过 setter 更新状态;当下一个值取决于前一个值时,优先使用函数式更新器(setCount(prev => prev + 1))。
核心 Hooks 概览
只能在组件或自定义 Hook 的顶层调用 Hook,不能在条件语句、循环或嵌套函数中调用。此规则可确保每次渲染时 Hook 的调用顺序保持稳定。
useState — 组件本地状态
保存一个值及其 setter。值发生变化时会重新渲染组件。
const [open, setOpen] = useState(false);
useEffect — 与外部系统同步
在渲染后运行以执行副作用:订阅、计时器、数据获取、手动 DOM 操作。依赖数组控制 Effect 何时重新运行。返回清理函数以清除订阅。
import { useEffect, useState } from 'react';
function WindowWidth() {
const [width, setWidth] = useState(window.innerWidth);
useEffect(() => {
const onResize = () => setWidth(window.innerWidth);
window.addEventListener('resize', onResize);
return () => window.removeEventListener('resize', onResize);
}, []); // empty deps: subscribe once on mount, clean up on unmount
return <span>{width}px</span>;
}
useRef — 在渲染间保持的可变值
保存可变值,但不会触发重新渲染。常见用途:引用 DOM 节点,或在渲染间保存值(计时器 ID、之前的值)。
import { useRef, useEffect } from 'react';
function AutoFocusInput() {
const inputRef = useRef<HTMLInputElement>(null);
useEffect(() => inputRef.current?.focus(), []);
return <input ref={inputRef} />;
}
useMemo — 缓存开销较大的计算
仅当依赖项变化时才重新计算值。仅在计算确实开销较大,或需要稳定传递给记忆化子组件的引用标识时使用。
const sorted = useMemo(() => items.slice().sort(compare), [items]);
useCallback — 稳定函数引用
只要依赖项相等,每次渲染都会返回同一个函数实例。将稳定的回调传递给记忆化子组件,或放入 Effect 依赖数组。
const handleSelect = useCallback((id: string) => onSelect(id), [onSelect]);
useContext — 无需逐层传递属性即可读取共享状态
读取组件树上层提供的上下文当前值。
import { createContext, useContext } from 'react';
const ThemeContext = createContext<'light' | 'dark'>('light');
function ThemedLabel() {
const theme = useContext(ThemeContext);
return <span className={theme}>Themed</span>;
}
关于可避免消费者不必要重新渲染的记忆化 Provider 模式,请参阅 react-hooks-composition。
组合模式
优先采用组合,而非配置。通过 children 传递内容,通过属性传递行为。
function Card({ title, children }: { title: string; children: React.ReactNode }) {
return (
<section className="card">
<h2>{title}</h2>
<div className="card-body">{children}</div>
</section>
);
}
// Usage
<Card title="Profile">
<Avatar />
<p>Bio text</p>
</Card>;
将共享逻辑提取到自定义 Hook(useSomething)中,而不是在组件间复制。保持组件小巧且职责单一。
条件渲染和列表渲染
使用 && 按条件渲染内容,或使用三元表达式在两种结果间选择。使用 map 渲染列表,并为每个项目提供基于其身份而非数组索引(顺序可能变化时)的稳定 key。
function TodoList({ todos }: { todos: { id: string; text: string; done: boolean }[] }) {
if (todos.length === 0) return <p>No todos yet.</p>;
return (
<ul>
{todos.map((todo) => (
<li key={todo.id}>
{todo.done ? <s>{todo.text}</s> : todo.text}
</li>
))}
</ul>
);
}
受控输入
受控输入的值来自状态,并通过 onChange 报告变化。状态是唯一可信来源。
import { useState } from 'react';
function NameField() {
const [name, setName] = useState('');
return (
<label>
Name
<input
value={name}
onChange={(event) => setName(event.target.value)}
/>
</label>
);
}
应避免的反模式
❌ 不要:直接修改状态
直接修改会跳过 setter,因此 React 不会重新渲染。
// BAD: mutates the array in place; React sees the same reference
function addItem(items: string[], next: string) {
items.push(next);
setItems(items);
}
// GOOD: create a new array so the reference changes
function addItem(items: string[], next: string) {
setItems([...items, next]);
}
❌ 不要:有条件地调用 Hooks
有条件地调用 Hook 会破坏 React 所依赖的稳定调用顺序。
// BAD: hook call order changes between renders
function Profile({ id }: { id?: string }) {
if (id) {
const data = useUser(id); // conditional hook call
return <span>{data.name}</span>;
}
return null;
}
// GOOD: call the hook unconditionally; branch on its result
function Profile({ id }: { id?: string }) {
const data = useUser(id); // useUser must accept an undefined id (no fetch / returns null) so the hook is always called
if (!id || !data) return null;
return <span>{data.name}</span>;
}
❌ 不要:将数组索引用作可重排列表的 key
当项目移动时,索引 key 会导致 React 错误地归属状态。
// BAD: index key breaks on reorder/insert/delete
{items.map((item, i) => <Row key={i} item={item} />)}
// GOOD: stable identity key
{items.map((item) => <Row key={item.id} item={item} />)}
何时使用相邻技能
react-hooks-composition:高级自定义 Hook 组合——基于 SWR 的数据获取、具有双重加载状态的防抖搜索、记忆化上下文提供程序,以及可复用的异步状态 Hook。react-state-machine:使用 XState v5 显式建模有限状态机,适用于复杂流程(多步骤表单、媒体播放器、带动画的模态框),确保不可能出现的状态无法表示。react-advanced:React 19 平台功能与渲染架构——React Compiler(自动记忆化)、并发渲染、use()Hook、Actions、虚拟化、代码拆分和 RSC 边界。
最佳实践总结
- 组件返回 JSX:使用 PascalCase 名称,并返回单个根元素或片段。
- Props 只读:向下传递数据;共享状态时,将状态提升到共同位置。
- 以不可变方式更新状态:使用 setter,优先采用函数式更新器。
- 只在顶层调用 Hook:绝不要有条件地调用 Hook。
- 副作用用于同步外部系统:通过依赖项限定作用范围,并清理订阅。
- 有意进行记忆化:对开销较大的操作或需要稳定标识的值使用 useMemo/useCallback,而非默认使用。
- 稳定的 key:根据标识而非数组索引为列表项设置 key。
- 受控输入:状态是唯一真实来源。