([]);
const selectedContact = useMemo(
() => contacts.find(c => c.id === selectedId),
[contacts, selectedId]
);
return (
{/* 左侧:联系人列表 */}
{/* 右侧:聊天窗口 */}
m.contactId === selectedId)}
onSend={(text) => setMessages(prev => [...prev, { text, contactId: selectedId!, timestamp: Date.now() }])}
/>
);
}
```
> [!diagram] 状态提升流程
> ```mermaid
> graph LR
> A[ContactList] -- "onSelect(id)" --> P[ChatApp - State]
> P -- "contact" --> B[ChatWindow]
> P -- "onSend(text)" --> P
> B -- "sendMessage(text)" --> P
> style P fill:#4FC08D,color:#fff
> ```
> [!tip] 何时应该使用状态提升?
> 当兄弟组件数量少(≤ 3 个)、关系固定、状态不频繁变化时,状态提升比引入状态管理库更简单、更可维护。
## 状态管理库方案
当状态需要在整个应用中流转、涉及复杂操作逻辑或多条副作用时,Zustand / Redux Toolkit 等库提供了集中式状态容器。
```tsx
// Zustand:极简 API,按 slice 订阅避免全量重渲染
import { create } from "zustand";
interface CartState {
items: CartItem[];
addItem: (item: CartItem) => void;
removeItem: (id: string) => void;
}
const useCartStore = create((set) => ({
items: [],
addItem: (item) => set(state => ({ items: [...state.items, item] })),
removeItem: (id) => set(state => ({ items: state.items.filter(i => i.id !== id) })),
}));
function ProductCard({ product }: { product: Product }) {
const addItem = useCartStore(s => s.addItem); // 精确订阅,仅在 addItem 引用变化时重渲染
return ;
}
function CartIcon() {
const items = useCartStore(s => s.items); // 仅 items 变化时重渲染
return {items.length};
}
// 两者毫无关联,但共享同一份状态
```
> [!note] Zustand vs Redux Toolkit 选型建议
> - **Zustand**:API 简洁、样板代码极少、支持 immer 中间件,适合中小型项目和个人项目
> - **Redux Toolkit**:生态成熟、DevTools 体验好、middleware 体系完善(thunk/saga),适合大型团队协作项目
> - 详见 [[hhs/REACT/3. 生态工具篇/09-状态管理.md]]
## Ref Imperative API(命令式通信)
大多数情况下 React 推崇声明式通信(Props + Callback),但在需要**直接操控子组件实例行为**时使用 refs。典型场景:触发自定义验证、聚焦输入框、播放动画。
```tsx
const formRef = useRef(null);
function Parent() {
const handleSubmit = () => {
formRef.current?.validate(); // 命令子组件执行
formRef.current?.reset();
};
return (
<>
>
);
}
const ChildForm = forwardRef((props, ref) => {
useImperativeHandle(ref, () => ({
validate: () => validator.validate(),
reset: () => setFields(initialValues),
}));
return ;
});
```
> [!warning] 谨慎使用 Imperative Refs
> Imperative API 打破了 React 的声明式范式。能用 declarative(状态驱动 UI)解决的问题,永远不要上 imperative(直接操控 DOM)。过度使用会导致:难以测试、时序 bug、调试困难。
## 决策树
```mermaid
graph TD
START["需要组件通信?"] -->|"否"| DONE["无需处理 ✅"]
START -->|"是"| RANGE["通信范围?"]
RANGE --> PARENT_CHILD["仅父子两层
(1-2 级深度)"]
RANGE --> DEEP["多层级穿透
(≥ 3 级深度)"]
RANGE --> SIBLING["兄弟组件 / 无关组件"]
RANGE --> IMPERATIVE["需命令式调用子组件方法"]
PARENT_CHILD --> PROP["Props + Callback ✅
简单、直观、可追踪"]
DEEP --> CTX["Context ✅
配合 useReducer 保证性能"]
SIBLING --> SLIFTING["状态提升到共同父 ✅"]
SIBLING --> STORE["状态管理库(复杂场景)"]
IMPERATIVE --> REF["forwardRef +
useImperativeHandle ✅"]
style PROP fill:#4FC08D,color:#fff
style CTX fill:#F5A87D,color:#000
style SLIFTING fill:#61DAFB,color:#000
style STORE fill:#C084FC,color:#fff
style REF fill:#A0AEC0,color:#000
```
## 关联笔记
- [[hhs/REACT/1. 基础篇/03-组件与 Props.md]] — Props 类型校验、组件拆分原则
- [[hhs/REACT/2. Hooks 篇/05-核心 Hooks.md]] — useContext / useRef 原理
- [[hhs/REACT/2. Hooks 篇/06-性能优化 Hooks.md]] — 配合 Context 的性能优化手段
- [[hhs/REACT/4. 进阶篇/12-HOC 与 Render Props.md]] — 高阶组件与 Render Props 进阶
- [[hhs/REACT/3. 生态工具篇/09-状态管理.md]] — Zustand / Redux Toolkit 选型对比
- [[hhs/REACT/5. 工程实践篇/15-性能优化.md]] — React.memo、虚拟列表、Bundle 分析