前言
如果你知道 vue 组件传值的方式,其实 react 也不难理解。组件传值无非父向子传值、子向父传值、兄弟传值、跨组件传值以及提供一个状态管理容器进行传值。好啦,我要开始行动啦!
一、父组件向子组件传值
步骤
- 父组件提供要传递的
state数据 - 给子组件标签添加属性,值为
state中的数据 - 子组件中通过
props接收父组件中传递的数据- 函数组件通过参数
props接收数据 - 类组件通过
this.props接收数据
- 函数组件通过参数
1.父组件把 state 中的数据作为属性值传递给子组件
App.js
import React from 'react'
// 导入子组件:函数组件和类组件
import FunCom1 from './components/FunCom1'
import FunCom2 from './components/FunCom2'
import ClassCom from './components/ClassCom'
class App extends React.Component {
state = {
name: 'Lucy',
age: 18
}
render() {
return <div className="App">
app
<FunCom1 name={this.state.name}></FunCom1>
<hr />
<FunCom2 msg="快快长大"></FunCom2>
<hr />
<ClassCom age={this.state.age}></ClassCom>
</div>
}
}
export default App
2.子组件通过 props/this.props 接收父组件传递过来的值
ClassCom.js
import React from 'react'
// ◆类组件:通过 this.props 接收
class ClassCom extends React.Component {
render() {
return <div>我是一个 类组件 ClassCom
<br />
<p>爸爸说我 {this.props.age}岁了</p>
</div>
}
}
export default ClassCom
FunCom1.js
// ◆普通函数组件 1:通过 props 接收
function FunCom1(props) {
return <div>我是 函数组件 FunCom1
<br />
<p>爸爸说我叫:{props.name}</p>
</div>
}
export default FunCom1
FunCom2.js
// ◆箭头函数组件 2:通过 props 接收值
const FunCom2 = (props) => {
return <div>我是 函数组件 FunCom2
<p>爸爸说:{props.msg}</p>
</div>
}
export default FunCom2
3.总结 props 的特点
- 可以给组件传递任意类型的数据
props是只读的,不允许修改props的数据- 注意:在类组件中使用的时候,需要把 props 传递给 super() ,否则构造函数无法获取到
propsClassCom.js子组件(类组件)
/* eslint-disable no-useless-constructor */
import React from 'react'
class ClassCom extends React.Component {
constructor(props) {
// ◆ 推荐将 props 传递给父类构造函数
super(props)
}
render() {
return <div>我是一个 类组件 ClassCom
<br />
<p>爸爸说我 {this.props.age}岁了</p>
</div>
}
}
export default ClassCom
二、子组件向父组件传值
步骤
- 父组件提供一个回调函数(用于接收数据)
- 将该函数作为属性的值,传递给子组件
- 子组件通过
props/this.props调用回调函数 - 将子组件的数据作为参数传递给回调函数
1.父组件提供回调函数,作为属性值传递给子组件
App.js
import React from 'react'
// 导入子组件:函数组件和类组件
import FunCom1 from './components/FunCom1'
import FunCom2 from './components/FunCom2'
import ClassCom from './components/ClassCom'
class App extends React.Component {
state={
name:'',
age:'',
msg:'',
}
getFunCom1Age = (age) => {
this.setState({
age:age
})
}
getFunCom2Name = (name) => {
this.setState({
name:name
})
}
getClassComMsg = (msg) => {
this.setState({
msg:msg
})
}
render() {
return <div className="App">
app
<p>收到 儿子 FunCom1 的讯息: {this.state.age}</p>
<p>收到 女儿 FunCom2 的讯息: {this.state.name}</p>
<p>收到 儿子 ClassCom 的讯息: {this.state.msg}</p>
<FunCom1 getAge={this.getFunCom1Age}></FunCom1>
<hr />
<FunCom2 getName={this.getFunCom2Name}></FunCom2>
<hr />
<ClassCom getMsg={this.getClassComMsg}></ClassCom>
</div>
}
}
export default App
2.子组件在调用父组件传递过来的函数的同时,捎带参数,就实现了子传父
FunCom1.js
// ◆子组件 FunCom1 接收函数并且调用
function FunCom1(props) {
const clickHandler=()=>{
props.getAge('爸爸,您今年60岁啦!')
}
return <div>我是 函数组件 FunCom1
<br />
<button onClick={clickHandler}>点我给 父组件传讯息</button>
</div>
}
export default FunCom1
FunCom2.js
// ◆子组件 FunCom2 接收函数并且调用
const FunCom2 = (props) => {
const clickHandler=()=>{
props.getName('爸爸,我是 Lucy 呀')
}
return <div>我是 函数组件 FunCom2
<br />
<button onClick={clickHandler}>点我给 父组件传讯息</button>
</div>
}
export default FunCom2
ClassCom.js
// ◆子组件 ClassCom 接收函数并且调用
import React from 'react'
class ClassCom extends React.Component {
state={
ClassComMsg:'爸爸,身体健康!'
}
clickHandler=()=>{
this.props.getMsg(this.state.ClassComMsg)
}
render() {
return <div>我是一个 类组件 ClassCom
<br />
<button onClick={this.clickHandler}>点我给 父组件传讯息</button>
</div>
}
}
export default ClassCom
子传父的核心:要想实现子传父,必先实现父传子
三、兄弟组件组件传值
即将共享状态提升到最近的公共父组件中,由公共父组件管理这个状态
步骤:
- 父组件提供一个回调函数(用于接收数据)
- 将该函数作为属性的值,传递给子组件
- 子组件通过
props/this.props调用回调函数 - 将子组件的数据作为参数传递给回调函数
- 父组件在回调函数中把参数赋值给 state 中状态值
- 父组件中把状态值 作为属性值传递给另外一个子组件
- 另外一个子组件 通过
props/this.props接收
1.状态提升到父组件,父组件把回调函数作为属性值传递给子组件
App.js
import React from 'react'
// 导入子组件:函数组件和类组件
import Sister from './components/Sister'
import Brother from './components/Brother'
class App extends React.Component {
state = {
brother: '',
sister: '',
}
//◆哥哥→妹妹: 父传给哥哥,哥哥再传给父,父再传给妹妹
brotherHandler = (msg) => {
this.setState({
brother: msg
})
}
//◆妹妹→哥哥:父传给妹妹,妹妹再传给父,父再传给哥哥
sisterHandler = (msg) => {
this.setState({
sister: msg
})
}
render() {
return <div className="App">
app
<Brother brotherFun={this.brotherHandler} msgfromSis={this.state.sister}></Brother>
<hr />
<Sister msgfromBro={this.state.brother} sisterFun={this.sisterHandler}></Sister>
<hr />
</div>
}
}
export default App
2.子组件在特定时期 调用 父组件传过来的函数,传递实参给父组件,触发状态值变化
Brother.js
import React from 'react'
// 哥哥组件:向妹妹组件传消息,也接收妹妹传过来的消息
class Brother extends React.Component {
brother=()=>{
this.props.brotherFun('老妹,我是哥哥,给我介绍个女朋友!')
}
render() {
return <div>
编程不仅仅是技术,还是艺术!Brother
<br />
<p>收到妹妹传过来的消息:{this.props.msgfromSis}</p>
<button onClick={this.brother}>按钮:点击哥哥传给妹妹</button>
</div>
}
}
export default Brother
3.父组件把状态值作为属性传递给另一个子组件,这就实现了兄弟组件传值
Sister.js
import React from 'react'
// ◆妹妹组件:接收哥哥组件传过来的消息,也向哥哥组件传消息
const Sister = (props) => {
const sister = () => {
props.sisterFun('哥哥好,我是妹妹,给我介绍个男盆友')
}
return <div>
编程不仅仅是技术,还是艺术!Sister
<p>收到哥哥的消息:{props.msgfromBro}</p>
<button onClick={sister}>按钮:点击妹妹传哥哥</button>
</div>
}
export default Sister
兄弟组件传值的核心思想:状态提升
四、跨组件传值
步骤
- 调用 React. createContext() 创建 Provider(提供数据) 和 Consumer(消费数据) 两个组件。
- 使用 Provider 组件作为父节点
- 设置 value 属性,表示要传递的数据
- 调用 Consumer 组件接收数据。
1.导入并调用 createContext 方法,从结果中解构出 Provider, Consumer 组件
context.js
// 1.导入 react
import React from 'react'
// Provider传,Consumer收,需要一个中间人,有点像 eventBus
// 2.导入并调用createContext方法,从结果中解构出 Provider, Consumer 组件
export const {Provider,Consumer}=React.createContext()
2.使用 Provider 组件包裹根组件,并通过 value 属性提供要共享的数据
App.js
import React from 'react'
// 导入 Parent 组件
import Parent from './components/Parent'
// 导入 Uncle 组件
import Uncle from './components/Uncle'
// ◆导入 Provider
import { Provider } from './components/context'
class App extends React.Component {
state={
obj:{
name:'Jom',
age:20
}
}
render() {
// return (<Provider value={this.state.obj}>
// 法2:解构
return (<Provider
value={{name:this.state.obj.name,age:this.state.obj.age}}>
<div className="App">
app
<Parent></Parent>
<hr />
<Uncle></Uncle>
</div>
</Provider>)
}
}
export default App
3.在任意后代组件中,使用第1步中导出的Consumer组件包裹整个组件
Parent.js
import React from 'react'
// Parent 组件
// 导入 Son 组件
import Son from './Son'
// ◆ 导入 Consumer
import { Consumer } from './context'
class Parent extends React.Component {
render() {
// return (<Consumer>
// {(data)=><div>
// 编程不仅仅是技术,还是艺术!Parent
// <p>Jom,你今年{data.age}岁了,要懂事啦!</p>
// <hr />
// <Son></Son>
// </div>}
// </Consumer>)
// 法2:解构
return (<Consumer>
{({age})=><div>
编程不仅仅是技术,还是艺术!Parent
<p>Jom,你今年{age}岁了,要懂事啦!</p>
<hr />
<Son></Son>
</div>}
</Consumer>)
}
}
export default Parent
Uncle.js
import React from 'react'
// Uncle 组件
// ◆导入 Consumer
import { Consumer } from './context'
const Uncle = () => {
// 这里 的 data 是形参,会自动接收Provider中传入的数据
// return (<Consumer>
// {(data) => <div>
// 编程不仅仅是技术,还是艺术!Uncle
// <p>{data.name}你好,听说你{data.age}岁了</p>
// </div>}
// </Consumer>)
// 法2 :解构
return (<Consumer>
{({name,age}) => <div>
编程不仅仅是技术,还是艺术!Uncle
<p>{name}你好,听说你{age}岁了</p>
</div>}
</Consumer>)
}
export default Uncle
Son.js
import React from 'react'
// Son 组件
// ◆ 导入 Consumer
import { Consumer } from './context'
const Son = () => {
// 这里 的 data 是形参,会自动接收Provider中传入的数据
// return (<Consumer>
// {(data) => <div>
// 编程不仅仅是技术,还是艺术!Son
// <p>爷爷给我取了名字:{data.name}</p>
// </div>}
// </Consumer>)
// 法2:解构
return (<Consumer>
{({name}) => <div>
编程不仅仅是技术,还是艺术!Son
<p>我的名字是爷爷给我取的:{name}</p>
</div>}
</Consumer>)
}
export default Son