还不会 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。每种方法都有其适用的场景和优缺点,还介绍了四种不同情况下的通讯方法,选择合适的通讯方式,可以使我们的应用更加高效、可维护。希望本文对你有所帮助,如果你有任何疑问或建议,欢迎留言交流!

相关推荐
多多*3 分钟前
Spring之Bean的初始化 Bean的生命周期 全站式解析
java·开发语言·前端·数据库·后端·spring·servlet
linweidong7 分钟前
在企业级应用中,你如何构建一个全面的前端测试策略,包括单元测试、集成测试、端到端测试
前端·selenium·单元测试·集成测试·前端面试·mocha·前端面经
满怀101527 分钟前
【HTML 全栈进阶】从语义化到现代 Web 开发实战
前端·html
东锋1.338 分钟前
前端动画库 Anime.js 的V4 版本,兼容 Vue、React
前端·javascript·vue.js
满怀10151 小时前
【Flask全栈开发指南】从零构建企业级Web应用
前端·python·flask·后端开发·全栈开发
小杨升级打怪中1 小时前
前端面经-webpack篇--定义、配置、构建流程、 Loader、Tree Shaking、懒加载与预加载、代码分割、 Plugin 机制
前端·webpack·node.js
每次的天空1 小时前
Android第三次面试总结之网络篇补充
android·网络·面试
Yvonne爱编码2 小时前
CSS- 4.4 固定定位(fixed)& 咖啡售卖官网实例
前端·css·html·状态模式·hbuilder
SuperherRo2 小时前
Web开发-JavaEE应用&SpringBoot栈&SnakeYaml反序列化链&JAR&WAR&构建打包
前端·java-ee·jar·反序列化·war·snakeyaml
大帅不是我2 小时前
Python多进程编程执行任务
java·前端·python