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>
<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> 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也可以分别创建成一个文件夹,方便管理)
//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} 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>
)
}
效果:
5.总结
推荐使用:
- 父子组件:props
- 兄弟组件:消息订阅-发布,react-redux
- 祖孙组件(跨级组件):消息订阅-发布、react-redux