还不会 React 组件通讯吗?包教会好吧

React 组件通讯

引言

在构建复杂的 React 应用时,组件间的通讯是一个至关重要的环节。无论是父子组件之间的简单数据传递,还是跨层级组件之间的状态共享,掌握高效的通讯方式能够显著提升应用的可维护性和开发效率。本文将详细介绍几种常用的 React 组件间通讯方法,包括 Props回调函数Context API,以及不同关系的组件之间的通讯。

(一)父组件向子组件传递值

Props 传值

父组件可以通过 props 将数据传递给子组件,这是最常见和最基本的方式。

1. 示例代码
jsx 复制代码
// 父组件
import React from 'react';
import ChildComponent from './ChildComponent';

function ParentComponent() {
  const text = 'Hello from Parent';

  return (
    <div>
      <h1>Parent Component</h1>
      <ChildComponent message={text} />
    </div>
  );
}

// 子组件
import React from 'react';

function ChildComponent(props) {
  return (
    <div>
      <h2>Child Component</h2>
      <p>{props.message}</p>
    </div>
  );
}

export default ParentComponent;
2. 详细讲解
  1. 父组件

    • 定义了一个变量 text,赋值为 'Hello from Parent'
    • 在返回的 JSX 中,通过 <ChildComponent message={text} /> 创建了一个 ChildComponent 的实例,将 message 作为 props 传递给 ChildComponent
  2. 子组件

    • 接收 props 作为参数。(props 是一个特殊的参数,它包含了所有从父组件传递过来的属性,我们可以通过 props 对象对这些属性进行访问。)
    • 在 JSX 中,在 ChildComponent 内部,我们可以像访问 JS 对象的属性一样来访问 props 中的数据。以上代码中,我们通过 {props.message} 访问传递过来的 message 属性。

(二)子组件向父组件传递值

通过回调函数传递值

子组件可以通过回调函数将数据传递给父组件。父组件将回调函数作为 props 传递给子组件,子组件在需要的时候调用这个回调函数。

1. 示例代码
jsx 复制代码
// 父组件
import React, { useState } from 'react';
import ChildComponent from './ChildComponent';

function ParentComponent() {
  // 响应式更新数据,效果类似 vue 中的 ref
  const [message, setMessage] = useState('');

  // 回调函数,接收子组件传递的数据 childData 并使用 setMessage 更新父组件的 message 状态
  const handleCallback = (childData) => {
    setMessage(childData);
  };

  return (
    <div>
      <h1>Parent Component</h1>
      <p>Message from Child: {message}</p>
      <ChildComponent parentCallback={handleCallback} />
      // 创建了一个 ChildComponent 的实例,并通过 parentCallback 属性传了 handleCallback 函数
    </div>
  );
}

// 子组件
import React from 'react';

// props 是一个对象,包含了所有从父组件传递过来的属性
function ChildComponent(props) {
  // 当按钮被点击时调用该函数,通过调用父组件传递过来的回调函数,并传递字符串 'Hello from Child' 作为参数
  const sendDataToParent = () => {
    props.parentCallback('Hello from Child');
  };

  return (
    <div>
      <h2>Child Component</h2>
      <button onClick={sendDataToParent}>Send Message to Parent</button>
    </div>
  );
}

export default ParentComponent;
2. 详细讲解
  1. 父组件

    • 使用 useState 钩子定义一个状态变量 message 和一个更新函数 setMessage
    • 定义一个回调函数 handleCallback,该函数接收子组件传递的数据并更新 message 状态。
    • 在返回的 JSX 中,通过 <ChildComponent parentCallback={handleCallback} />handleCallback 作为 props 传递给 ChildComponent
  2. 子组件

    • 接收 props 作为参数。
    • 定义一个函数 sendDataToParent,在按钮点击事件中调用 props.parentCallback 并传递 'Hello from Child' 作为参数。

(三)兄弟组件通讯

兄弟组件通讯,顾名思义,就是两个组件拥有相同的父组件,则这两个组件互为兄弟组件。最直接的,我们可以通过一次子传父+一次父传子=一次兄弟组件通讯。我们当回顾上述知识,并让大家可以更深刻地了解兄弟组件通讯,再使用父子组件通讯的方法完成该要求。

通过父组件传递

1. 知识点解析
  • 状态提升 :当多个组件需要反映相同的数据时,应该将这个数据的状态提升到它们最近的共同父组件中。这种方式可以使状态管理更加集中,减少重复代码。

  • Props :在 React 中,父组件可以通过props向子组件传递数据和函数。子组件不能直接修改父组件的状态,但可以通过回调函数(如onInput)将数据传递回父组件。

  • useState Hook:这是一个用于在函数组件中添加状态的 Hook。它返回一个状态变量和一个更新该状态的函数。

2. 代码分析
父组件 App.js
Jsx 复制代码
import React, { useState } from 'react';
import ChildA from './ChildA';
import ChildB from './ChildB';

function App() {
  // 这里定义了一个状态 shared 和一个更新该状态的函数 setShared
  const [shared, setShared] = useState('');

  return (
    <div>
      <h1>通过父组件传递</h1>
      // 父组件将 setShared 作为 onInput 属性传递给 ChildA
      <ChildA onInput={setShared} />
      // 同理
      <ChildB text={shared} />
    </div>
  );
}

export default App;
子组件 ChildA.js
Jsx 复制代码
import React from 'react';

function ChildA({ onInput }) {
  return (
    <div>
      <h2>ChildA</h2>
      <input type="text" onChange={(e) => onInput(e.target.value)} placeholder="输入文本" />
    </div>
  );
}

export default ChildA;
  • onInput 属性ChildA接收一个onInput属性,这是一个函数。当输入框的值发生变化时,调用onInput并将新的值传递给它。这实际上是在调用父组件中的setShared函数,从而更新父组件的状态。
子组件 ChildB.js
Jsx 复制代码
import React from 'react';

function ChildB({ text }) {
  return (
    <div>
      <h2>ChildB</h2>
      // 这是从父组件传递过来的 shared
      <p>{text}</p>
    </div>
  );
}

export default ChildB;

(四)祖孙组件通讯

介绍完父子组件通讯,我们再来聊聊祖孙组件的通讯。让我们设想一下,此时有一个祖父组件,一个父组件和一个子组件,即祖父组件和子组件互为祖孙组件,我们可以如何使这两个祖孙组件之间完成传值操作呢?首先,机智如你,肯定可以想到可以完成两个父传子=一次祖孙传值。Yes,通过我们上面的讲解就可以解决这个问题,我们就不在此处对此方法进行赘述,相信你可以自己完成,接下来我们来学习一个更高阶的方法,使用 React 中的Context API可以高效的完成该操作。

使用 Context API

1. 知识点解析
  • Context API :提供了一种在组件树中传递数据的方式,而无需手动将props一层层传递下去。

  • createContext :创建一个Context对象。

  • <MyContext.Provider> :一旦有了 Context 对象,就可以使用 <MyContext.Provider> 组件来为树中的所有组件提供这个 Context。Provider接受一个 value 属性,该属性是你要传递的数据。任何在这个Provider下的组件都可以访问到这个值。(即辈分高的组件可以给任意低辈分的组件传值,但反之则不行)

  • useContext Hook :在需要使用 Context 的组件中,可以使用 <MyContext.Consumer> 组件或 useContext Hook(如果是在函数组件中)来订阅 Context。

2. 代码示例
创建 Context
Jsx 复制代码
import React, { createContext, useContext, useState } from 'react';

// 创建 Context 对象
const MyContext = createContext();

function Grandparent() {
  const [shared, setShared] = useState('');

  return (
    // 将 shared 和 setShared 作为 value 属性传递给所有子组件,意味着任何在 MyContext.Provider 内部的组件都可以访问这两个值
    <MyContext.Provider value={{ shared, setShared }}>
      <div>
        <h1>使用Context API</h1>
        <Parent />
      </div>
    </MyContext.Provider>
  );
}

export default Grandparent;
父组件 Parent.js
Jsx 复制代码
import React from 'react';
import Child from './Child';

function Parent() {
  return (
    <div>
      <h2>Parent</h2>
      <Child />
    </div>
  );
}

export default Parent;
子组件 Child.js
Jsx 复制代码
import React, { useContext } from 'react';
import { MyContext } from './Grandparent';

function Child() {
  // 使用 useContext(MyContext) 钩子来订阅 MyContext,并将解构出的 shared 和 setShared 用于组件内部
  const { shared, setShared } = useContext(MyContext);

  return (
    <div>
      <h3>Child</h3>
      <input
        type="text"
        value={shared}
        onChange={(e) => setShared(e.target.value)}
        placeholder="输入文本"
      />
      <p>当前输入: {shared}</p>
    </div>
  );
}

export default Child;
3.代码分析
  • Grandparent 组件 :创建一个Context对象MyContext,并通过<MyContext.Provider>sharedsetShared传递给其子组件树。

  • Parent 组件 :没有任何特殊逻辑,只是渲染Child组件。

  • Child 组件 :通过useContext Hook订阅MyContext,获取sharedsetShared。显示当前状态并在输入框变化时调用setShared更新状态。

这段代码很好地展示了如何利用 Context API 实现跨层级组件之间的状态管理和通信。

4. 方法对比
  • 通过中间的父组件传递:适用于简单的祖孙组件通信,特别是当组件层次结构较浅时。这种方式清晰明了,但可能会导致"prop-drilling"问题。
  • 使用 Context API:适用于深层次嵌套的组件树,可以避免"prop-drilling"问题,使状态管理更加灵活和集中。

总结

通过本文的介绍,我们了解了 React 中几种常用的组件间通讯方法,包括 PropsContext API。每种方法都有其适用的场景和优缺点,还介绍了四种不同情况下的通讯方法,选择合适的通讯方式,可以使我们的应用更加高效、可维护。希望本文对你有所帮助,如果你有任何疑问或建议,欢迎留言交流!

相关推荐
OpenTiny社区14 分钟前
Node.js技术原理分析系列——Node.js的perf_hooks模块作用和用法
前端·node.js
菲力蒲LY18 分钟前
输入搜索、分组展示选项、下拉选取,全局跳转页,el-select 实现 —— 后端数据处理代码,抛砖引玉展思路
java·前端·mybatis
飞天大河豚1 小时前
2025前端框架最新组件解析与实战技巧:Vue与React的革新之路
vue.js·react.js·前端框架
MickeyCV2 小时前
Nginx学习笔记:常用命令&端口占用报错解决&Nginx核心配置文件解读
前端·nginx
祈澈菇凉2 小时前
webpack和grunt以及gulp有什么不同?
前端·webpack·gulp
十步杀一人_千里不留行2 小时前
React Native 下拉选择组件首次点击失效问题的深入分析与解决
javascript·react native·react.js
zy0101012 小时前
HTML列表,表格和表单
前端·html
初辰ge2 小时前
【p-camera-h5】 一款开箱即用的H5相机插件,支持拍照、录像、动态水印与样式高度定制化。
前端·相机
HugeYLH2 小时前
解决npm问题:错误的代理设置
前端·npm·node.js
三天不学习3 小时前
Redis面试宝典【刷题系列】
数据库·redis·面试