This repository has been archived on 2026-05-24. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
all-in-kingsoft/hhs/REACT/4. 进阶篇/11-组件通信模式.md
T
2026-04-29 22:19:51 +08:00

4.8 KiB
Raw Blame History

tags, create time
tags create time
React
Component Communication
Props
Context
Frontend
2026-04-29 22:10

组件通信模式

概述

React 中父子组件之间的数据流动有多种方式。理解每种模式的适用场景和性能影响,能够避免过度设计或通信瓶颈。本文档从简单到复杂,梳理完整的通信方案谱系。

通信方向全景图

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(属性逐层透传)

问题场景

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(子 → 父)

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 跨层级通信

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} 对象

状态管理库方案

// 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(命令式通信)

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>;
});

决策树

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

关联笔记