React组件间通信

React组件间通信

一、父->子通信:Props

最基础也是最常用的方式。

  • 父组件通过props向子组件传递数据或函数
  • 子组件通过接受props来使用这些数据或调用函数

使用场景:组件层级清晰,数据只需要自上而下传递。

tsx 复制代码
function Parent() {
  const message = "hello from parent";
  return <Child message={message}></Child>;
}

function Child(props: { message: string }) {
  return <p>{props.message}</p>;
}

二、子->父组件:回调函数

React中数据是单向流动的,因此子组件如需向父组件传递数据,需依赖父组件提供的回调。

  • 父组件定义回调函数并通过props传给子组件
  • 子组件调用该回调,将数据"抛回"给父组件

适用场景: 用户操作需要让父组件更新数据,例如点击事件、输入框数据回传等。

tsx 复制代码
function Parent() {
  const handleChildData = (data: string) => {
    console.log("data from child:", data);
  };
  return <Child onSendData={handleChildData}></Child>;
}

function Child({ onSendData }: { onSendData: (data: string) => void }) {
  return (
    <button onClick={() => onSendData("hello from 'child")}>send data</button>
  );
}

三、兄弟组件通信

兄弟组件之间无法直接通信,一般通过提升state到最近的共同父组件实现:

  1. 将共享数据提升到共同父组件
  2. 父组件通过props向两个子组件传递数据和修改方法

适用场景:界面中两个兄弟组件需要共享状态或相互影响。

tsx 复制代码
function SiblingA({data}:{data:string}){
  return (
    <p>{data}</p>
  )
}
function SiblingB({onUpdateData}:{onUpdateData:(data: string)=> void}){
  return (
    <button onClick={()=>onUpdateData('123')}>update data</button>
  )
}
function Parent() {
  const [sharedData, setSharedData] = useState('Initial Data')
  return (
    <div>
      <SiblingA data={sharedData}></SiblingA>
      <SiblingB onUpdateData={(val)=>setSharedData(val)}></SiblingB>
    </div>
  )
}

四、跨层通信

当层级较深、props传递链条过长时,可以使用Context。

  • 提供方(Provider)在高层包裹组件树
  • 消费方(useContext)在任意组件中访问数据

适用场景: 主题、语言、多层共享状态等需要跨层访问的数据。

tsx 复制代码
const ThemeDefault = "light";
const ThemeContext = createContext(ThemeDefault);
const Context = () => {
  const [theme, setTheme] = useState(ThemeDefault);
  function handleTheme() {
    if (theme === "light") setTheme("dark");
    else setTheme("light");
  }
  return (
    <div>
      <h2>跨层通信</h2>
      <button onClick={handleTheme}>切换主题</button>
      <hr />
      <ThemeContext.Provider value={theme}>
        <ToolBar />
      </ThemeContext.Provider>
    </div>
  );
};
function ToolBar() {
  return <ThemeButton></ThemeButton>;
}
function ThemeButton() {
  const theme = useContext(ThemeContext);
  return (
    <button style={{ background: theme === "dark" ? "#333" : "#eee" }}>
      按钮
    </button>
  );
}

五、全局状态

当项目状态复杂时,可以使用全局状态管理工具(如Zustand、Redux、Jotai、Recoil)。

优点:

  • 数据全局可访问、可响应式更新
  • 跨页面、跨组件共享
  • 对大型项目尤为重要

适用场景:

  • 需要在多处使用的全局状态
  • 数据修改后需要触发多组件联动渲染
tsx 复制代码
const useStore = create((set) => ({
  count: 0,
  increment: ()=> set((state: { count: number }) => ({count: state.count + 1}))
}))

function Counter() {
  const {count, increment} = useStore() as {count:number,increment:()=>void}
  return (
    <div>
      <p>{count}</p>
      <button onClick={increment}>加</button>
    </div>
  )
}

六、事件总线

通过事件实例(如mitt或自定义emitter)实现任意组件间通信:

  • emitter.emit('event', data)发送消息
  • emitter.on('event', handler)监听消息

优点:

  • 无组件层级限制
  • 松耦合、灵活

适用场景:

  • 页面内独立组件之间的通知
  • 轻量级的跨组件事件触达
tsx 复制代码
// A组件中触发事件
function ComponentA() {
  return (
    <button onClick={() => emitter.emit("message", "A: hello component B")}>
      触发事件:向B组件传递消息
    </button>
  );
}

// B组件中接收消息
function ComponentB() {
  const [msg, setMsg] = useState("waiting msg");
  // 避免重复注册监听事件
  useEffect(() => {
    const hanlderEvent = (message: string) => {
      console.log(message);
      setMsg(message);
    };
    emitter.on("message", hanlderEvent);

    return () => {
      // 卸载组件时移除
      emitter.off("message", hanlderEvent);
    };
  }, []);
  return <p>{msg}</p>;
}

总结

通信方式 特点 场景
Props(父->子) 最基础、最直观 单向向下传递数据
回调(子->父) 子组件向父组件"汇报" 表单、操作事件回传
状态提升(兄弟通信) 通过共同父组件协调 兄弟组件共享状态
Context 解决props层层传递 多层级共享数据
全局状态 跨页面、跨业务共享 中大型项目
事件总线 任意组件互相通信 异步事件、低耦合通信
相关推荐
光影少年9 小时前
rn如何和原生进行通信,是单线程还是多线程,通信方式都有哪些
前端·react native·react.js·taro
用户479492835691514 小时前
React 终于出手了:彻底终结 useEffect 的"闭包陷阱"
前端·javascript·react.js
哈__15 小时前
React Native 鸿蒙跨平台开发:PixelRatio 实现鸿蒙端图片的高清显示
javascript·react native·react.js
wszy180915 小时前
外部链接跳转:从 App 打开浏览器的正确姿势
java·javascript·react native·react.js·harmonyos
wordbaby15 小时前
TanStack Router 实战:如何构建经典的“左侧菜单 + 右侧内容”后台布局
前端·react.js
爱吃奶酪的松鼠丶16 小时前
React长列表,性能优化。关于循环遍历的时候,key是用对象数据中的ID还是用索引
javascript·react.js·性能优化
哈__20 小时前
从入门小白到精通,玩转 React Native 鸿蒙跨平台开发:TouchableOpacity 触摸反馈组件
react native·react.js·harmonyos
古茗前端团队20 小时前
视频播放弱网提示实现
react.js
哈__21 小时前
入门小白到精通,玩转 React Native 鸿蒙跨平台开发:Button 按钮组件与点击事件
react native·react.js·harmonyos
哈__21 小时前
React Native 鸿蒙开发:内置 Share 模块实现无配置社交分享
javascript·react native·react.js