vault backup: 2026-04-29 22:19:51

This commit is contained in:
2026-04-29 22:19:51 +08:00
parent 0421a3c801
commit 94bc44ab8f
19 changed files with 4877 additions and 0 deletions
@@ -0,0 +1,187 @@
---
tags: [React, Component Communication, Props, Context, Frontend]
create time: 2026-04-29 22:10
---
# 组件通信模式
## 概述
React 中父子组件之间的数据流动有多种方式。理解每种模式的适用场景和性能影响,能够避免过度设计或通信瓶颈。本文档从简单到复杂,梳理完整的通信方案谱系。
## 通信方向全景图
```mermaid
graph TD
A["父 → 子"] --> B["Props(最基础)"]
A --> C["Context Provider(跨层级)"]
A --> D["状态管理库(全局共享)"]
E["子 → 父"] --> F["回调 Prop(事件驱动)"]
E --> G["refs(imperative)"]
H["兄弟组件"] --> I["状态提升到共同父组件"]
H --> J["通过共同祖先通信"]
H --> K["状态管理库 / 发布订阅"]
style B fill:#4FC08D,color:#fff
style C fill:#F5A87D,color:#000
style F fill:#61DAFB,color:#000
```
## Props Drill(属性逐层透传)
### 问题场景
```tsx
function App() {
const user = getUser();
return <Header user={user} />; // Header 不需要 user,但深层的 Avatar 需要!
}
function Header({ user }) {
return (
<nav>
<Logo /> {/* ❌ 无需 user,却接收了 */}
<Avatar user={user} /> {/* ✅ 需要 */}
</nav>
);
}
```
### 解决方案对比
| 方法 | 适合场景 | 额外依赖 |
|------|----------|---------|
| **Context** | 少量深层传递(主题、用户信息) | 无 |
| **自定义 Hook + Props 重组织** | 中等深度(3-4 层) | 无 |
| **状态管理库** | 频繁变化、多组件共享 | Zustand/Redux |
| **Render Prop / HOC** | 复用逻辑而非传值 | 无 |
## Callback Prop(子 → 父)
```tsx
interface FormProps {
onSubmit: (data: FormValues) => Promise<void>;
}
function LoginForm({ onSubmit }: FormProps) {
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
const data = collectFormData();
onSubmit(data); // 通知父组件
};
return <form onSubmit={handleSubmit}><Button type="submit">登录</Button></form>;
}
// 父组件
function App() {
const handleLogin = async (data: FormValues) => {
await api.login(data);
navigate("/dashboard");
};
return <LoginForm onSubmit={handleLogin} />;
}
```
> [!note] 为什么不用 props.children 做通信?
> children 是 UI 内容插槽,不是通信机制。通信用 callback prop 保持关注点分离。
## Context 跨层级通信
```tsx
const UserContext = createContext<User | null>(null);
function UserProfile({ children }: { children: React.ReactNode }) {
const user = useDatabaseUser(userId);
return (
<UserContext.Provider value={user}>
{/* Avatar、Settings、OrderHistory 任意深度都可消费 */}
{children}
</UserContext.Provider>
);
}
function OrderHistory() {
const user = useContext(UserContext); // 直接获取,无需中间层透传
return <div>{user?.orders?.map(...)}</div>;
}
```
> [!warning] Context 的性能陷阱
> - Provider value 对象每次渲染都是新引用 → 所有消费者重渲染
> - 解决:拆分 Context、或使用 `useReducer` 返回稳定的 `{state, dispatch}` 对象
## 状态管理库方案
```tsx
// Zustand 方案:任意两个组件共享 state,无需祖先后代关系
import { create } from "zustand";
const useCartStore = create((set) => ({
items: [],
addItem: (item) => set(state => ({ items: [...state.items, item] })),
}));
function ProductCard() {
const addItem = useCartStore(s => s.addItem);
return <button onClick={() => addItem(product)}>加入购物车</button>;
}
function CartIcon() {
const items = useCartStore(s => s.items);
return <Badge>{items.length}</Badge>;
}
// 两者毫无关联,但共享同一份状态
```
## Ref Imperative API(命令式通信)
```tsx
const formRef = useRef<FormHandle>(null);
function Parent() {
const handleSubmit = () => {
formRef.current?.validate(); // 命令子组件执行方法
formRef.current?.reset();
};
return <><ChildForm ref={formRef} /><button onClick={handleSubmit}>提交</button></>;
}
const ChildForm = forwardRef<FormHandle>((props, ref) => {
useImperativeHandle(ref, () => ({
validate: () => validator.validate(),
reset: () => setFields(initialValues),
}));
return <form>...</form>;
});
```
## 决策树
```mermaid
graph TD
A["需要通信?"] -->|"是"| B["通信范围?"]
B --> C["仅父子两层"]
B --> D["多层级穿透"]
B --> E["跨层级 + 兄弟之间"]
B --> F["需命令式调用子组件方法"]
C --> G["Props + Callback ✅"]
D --> H["Context ✅"]
E --> I["Zustand / Redux ✅"]
F --> J["forwardRef + useImperativeHandle ✅"]
style G fill:#4FC08D,color:#fff
style H fill:#61DAFB,color:#000
style I fill:#F5A87D,color:#000
style J fill:#A0AEC0,color:#000
```
## 关联笔记