React组件通信方式总结

1.props

实现父子组件之间的通信

//父组件
import './App.css';
import React, {useState } from 'react'
import Home from "./components/Home.jsx"

export default function App() {
  const [name,setName]=useState("zhangsan");
  return (
    <div>
      <Home name={name}/>
    </div>
  )
}


//子组件
import React from 'react'
export default function Home(props) {
  return (
    <div>name:{props.name}</div>
  )
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NwpwjVs5-1668410196354)(E:%5Ctypora_data%5C%E7%AC%94%E8%AE%B0%E5%9B%BE%E7%89%87%5Cimage-20221114104019924.png)]

2.context

在React中,Context提供了一种在组件之间共享数据的方法,而无需手动通过每个级别的props来传递数据。它可以让数据在组件树中共享,而无需显式地通过每个组件传递。

要使用Context,首先需要创建一个Context对象,并将要共享的数据存储在其中。然后,在需要使用该数据的组件中,可以使用useContext hook来获取该Context对象。

  • 创建一个Context对象
//myContext.jsx
import React from 'react';  
  
const MyContext = React.createContext();
- 在需要使用该数据的组件中,使用useContext hook获取该Context对象
```js
// MyComponent.jsx
import React from 'react';  
import MyContext from './myContext';  
  
function MyComponent() {  
  const value = React.useContext(MyContext);  
  return (  
    <div>  
      {value}  
    </div>  
  );  
}
  • 在父组件中使用Context Provider,将数据传递给子组件
//MyParentComponent.jsx
import React from 'react';  
import MyContext from './myContext';  
import MyChildComponent from './myChildComponent';  
  
function MyParentComponent() {  
  return (  
    <MyContext.Provider value="Hello, World!">  
      <MyChildComponent />  
    </MyContext.Provider>  
  );  
}

在这个例子中,MyParentComponent使用了MyContext.Provider组件,将数据"Hello, World!"传递给了MyChildComponent。MyChildComponent中的useContext hook获取了该数据,并将其渲染到了页面上。

context是一个全局变量,像是一个大容器,在任何地方都可以访问到,我们可以把要通信的信息放在context上,然后在其他组件中可以随意取到;但是React官方不建议使用大量context,尽管他可以减少逐层传递,但是当组件结构复杂的时候,我们并不知道context是从哪里传过来的;而且context是一个全局变量,全局变量正是导致应用走向混乱的罪魁祸首.

3.消息订阅发布:pubs-sub

props可以实现父子之间的通信,但是兄弟之间通信并没有提供相应的方法,想要实现就需要在多层组件之间一层一层传递,将信息传给共同的父组件,然后父组件传递给子组件的方式;

解决方式:

引入第三方库 PubSubJS,就能直接在触发事件的组件中发布消息,监听组件中订阅消息来实现兄弟组件的通信:

下载第三方库

npm install pubsub-js --save

使用

import React from 'react'
import PubSub from "pubsub-js"
import { Fragment } from 'react'
export default function Home(props) {
const send=()=>{
    //发布消息
    PubSub.publish("name",props.name)
}
  return (
    <Fragment>
      <div>name:{props.name}</div>
      &nbsp;&nbsp;&nbsp;<button onClick={send}>发布消息</button>
    </Fragment>
    
  )
}

import React,{useEffect,useState} from 'react'
import PubSub from 'pubsub-js'
export default function About() {
    const [name,setName]=useState("");
    useEffect(()=>{
        //订阅消息
       PubSub.subscribe("name",getName);
       return()=>{
           //组件卸载时,取消订阅
        PubSub.unsubscribe("name")
       }
    })
    const getName=(msg,data)=>{
       console.log("msg",msg)
       console.log("data",data)
       setName(data)
    }
  return (
    <div>&nbsp;&nbsp;&nbsp;name:{name}</div>
  )
}

4.集中管理 react-redux

React-Redux 是一个插件库,用于简化 React 中使用 Redux 。

下载

npm install redux react-redux --save

修改index.js

Provider 组件的使用:让所有组件都能获得状态数据,不必一个一个传递

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import { Provider } from 'react-redux';
import store from './redux/store';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
      <React.StrictMode>
      <Provider store={store}>
      <App />
    </Provider>
      </React.StrictMode>
);

创建redux文件夹,并创建如下文件(当要保存的状态比较的多的时候,action和reducer也可以分别创建成一个文件夹,方便管理)

image-20221114145615539

//student_reducer.js
/**
 * reducer的作用
 * 用于初始化状态,加工状态
 * 根据旧状态和action产生新状态
 */
export default function studentReducer(preState=[],action){
    const {type,data}=action;
    switch(type){
        case 'addStudent':
            //不要再原有的preState身上修改,因引preState虽然内容变了,但是数组地址没变,React会认为状态没有改变而不会重新渲染页面
            return  [...preState,data];
        default:
            return preState;
    }

}
//student_action.js
/**
*表示动作的对象,包含 2 个属性,type和data
*type :标识属性,值为字符串,唯一,必须属性
*data :数据属性,类型任意,可选属性
*/
export  function addAction(data){
    return {type:"addStudent",data:data}
}

//store.js
/**
*Redux 核心对象,内部维护着 state 和 reducer
*/
import {createStore,combineReducers} from "redux";
import studentReducer from "./student_reducer.js";
//汇中所有的reducers
const allReducer=combineReducers({
    students:studentReducer
})
const store=createStore(allReducer);
export default store;

使用:

useSelector(): 用户获取数据仓库store某一项数据,这个 hook 会订阅 redux store,所以每次 redux state有更新,useSelector() 里的 selector 就会重新计算一次,返回新的结果,并重新渲染当前组件

//Student.jsx
import React from 'react'
import { useSelector } from 'react-redux'
import { Fragment } from 'react'
export default function Student() {
       const students=useSelector(state=>state.students)
  return (
    <Fragment>
      <ul>
        {students.map((item)=>{
          return <li key={new Date()}>name:{item.name}&nbsp;&nbsp;&nbsp;age:{item.age}</li>
        })}
      </ul>
    </Fragment>
  )
}

useDispatch():更新数据

//Add.jsx
import React,{Fragment,useRef}from 'react'
import {useDispatch } from 'react-redux'
import { addAction } from '../redux/student_action';
export default function Student() {
   const dispatch=useDispatch();
   const name=useRef();
   const age=useRef();
   const add=()=>{
    console.log(name.current)
    const student={name:name.current.value,age:age.current.value}
    //更新数据
    dispatch(addAction(student))
   }
  return (
    <div>
        <Fragment>
        name:<input type="text" ref={name}/><br/>
        age:<input type="text" ref={age}/><br/>
        <button onClick={add}>添加</button>
    </Fragment>
    </div>
  )
}
//App.js

import './App.css';
import React from 'react'
import Student from "./components/Student.jsx"
import Add from "./components/Add.jsx"
export default function App() {
  return (
    <div>
      <Add/>
      <Student />
    </div>
  )
}

效果:
https://gitee.com/cao-yanlei/image/raw/master/img/202211141523325.gif

5.总结

推荐使用:

  • 父子组件:props
  • 兄弟组件:消息订阅-发布,react-redux
  • 祖孙组件(跨级组件):消息订阅-发布、react-redux
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值