前言:
最新在做react的B端项目、因为项目中没有用到Redux等数据管理库、所以涉及到了很多组件之前的数据传递和嵌套组件如何传递的方式,温故而知新 特此整理记录一下。
常见的组建通信的方式:
父子组件通信
子父组件通信
兄弟组件通信
爷孙通信(嵌套组件)
等等
代码环境:
react: ^16.13.0
react-dom:^16.8.2
父子组件通信:
通常来说是父组件通过props、refs等方式来调用子组件的方法和属性等;
props
: 子组件接受父组件的值进行视图更新
class 组件:
import React, { Component } from 'react'
// 子组件
class Child extends Component {
constructor(props) {
super(props)
this.state = {}
}
render() {
const { mun } = this.props;
return (
<>
这里是child子组件:
<p>{ mun }</p>
</>
)
}
}
// 父组件
class Parent extends Component {
constructor(props) {
super(props)
this.state = {
mun:1
}
}
handleParent = () => {
this.setState({
mun: this.state.mun + 1
})
}
render() {
const { mun } = this.state
return (
<>
<button onClick={this.handleParent}>我是父组件的按钮。你可以点击我</button>
<br />
<Child mun={mun} />
</>
)
}
}
export default Parent
Hooks组件:
import React, { useState } from 'react'
const Child = (props) => {
const { mun } = props;
return (
<>
这里是child子组件:
<p>{ mun }</p>
</>
)
}
const Parent = () =>{
const [mun, setMun] = useState(0)
const handleParent = () => {
setMun((value) => {
return value + 1
})
}
return (
<>
<button onClick={handleParent}>我是父组件的按钮。你可以点击我</button>
<br />
<Child mun={mun} />
</>
)
}
export default Parent
refs
:父组件通过声明ref拿到子组件的对象、进行操作子组件的对象方法
class 组件:
import React, { Component, createRef } from 'react'
// 子组件
class Child extends Component {
constructor(props) {
super(props)
this.state = {
mun:1
}
}
// 子组件累加累加
accumulation = () => {
this.setState({
mun: this.state.mun + 1
})
}
render() {
const { mun } = this.state
return (
<>
这里是child子组件:
<p>{ mun }</p>
</>
)
}
}
// 父组件
class Parent extends Component {
constructor(props) {
super(props)
// 通过ref控制
this.createRef = createRef()
this.state = {}
}
handleParent = () => {
this.createRef && this.createRef.current.accumulation()
}
render() {
return (
<>
<button onClick={this.handleParent}>我是父组件的按钮。你可以点击我</button>
<br />
<Child ref={this.createRef} />
</>
)
}
}
export default Parent
Hooks 组件:
注意
:在hooks中需要通过forwardRef
转发获取ref
的值,然后通过useImperativeHandle向父组件抛出子组件的方法。
import React, { useRef, useState, useImperativeHandle, forwardRef } from 'react'
const Child = forwardRef((_, ref) => {
const [mun, setMun] = useState(0)
// 累加方法
const accumulation = () => {
setMun((value) => {
return value + 1
})
}
// 给父组件抛出方法
useImperativeHandle(ref, () => ({
accumulation,
}), [accumulation]);
return (
<>
这里是child子组件:
<p>{ mun }</p>
</>
)
})
const Parent = () =>{
const ChildRef = useRef(null);
const handleParent = () => {
ChildRef.current && ChildRef.current.accumulation()
}
return (
<>
<button onClick={handleParent}>我是父组件的按钮。你可以点击我</button>
<br />
<Child ref={ChildRef} />
</>
)
}
export default Parent
子父组件通信:
子组件通过CallBack回调函数的方式来拿到父组件的方法或者属性等
Class 组件:
import React, { Component, createRef } from 'react'
// 子组件
class Child extends Component {
constructor(props) {
super(props)
this.state = {
mun:0
}
}
// 子组件累加累加
accumulation = () => {
const { handleParent } = this.props
const { mun } = this.state
this.setState({
mun:this.state.mun + 1
},() => {
handleParent(this.state.mun)
})
}
render() {
const { mun } = this.props
return (
<>
这里是child子组件:
{/* <p>{ mun }</p> */}
<button onClick={this.accumulation}>我是子组件的按钮、可以点击我</button>
</>
)
}
}
// 父组件
class Parent extends Component {
constructor(props) {
super(props)
// 通过ref控制
this.ChildRef = createRef()
this.state = {
getChildmun:0
}
}
handleParent = (_mun) => {
this.setState({
getChildmun:_mun
})
}
render() {
const { getChildmun } = this.state
return (
<>
<h2>我是父组件</h2>
<p>子组件控制的值:{ getChildmun }</p>
<br />
<Child handleParent={this.handleParent} />
</>
)
}
}
export default Parent
Hooks 组件:
import React, { useState, useEffect } from 'react'
const Child = (props) => {
const { handleParent } = props;
const [mun,setMun] = useState(0)
// 子组件累加累加
const accumulation = () => {
setMun((value) => {
return value + 1
})
}
useEffect(() => {
if(mun !== 0) {
handleParent(mun)
}
}, [mun]);
return (
<>
这里是child子组件:
<button onClick={accumulation}>我是子组件的按钮、可以点击我</button>
</>
)
}
const Parent = () =>{
const [getChildmun,setChildmun] = useState(0);
return (
<>
<h2>我是父组件</h2>
<p>子组件控制的值:{ getChildmun }</p>
<br />
<Child handleParent={(mun) => setChildmun(mun)} />
</>
)
}
export default Parent
兄弟组件通信:
兄弟组件通信一般都是在一个父组件下平级的两个兄弟组件、利用父组件当中介进行传递
Class 组件:
import React, { Component, createRef } from 'react'
// 子组件1
class Child1 extends Component {
constructor(props) {
super(props)
this.state = {
mun:0
}
}
render() {
const { brother } = this.props
return (
<>
<h2>我是Child1组件:{brother}</h2>
</>
)
}
}
// 子组件1
class Child2 extends Component {
constructor(props) {
super(props)
this.state = {
mun:0
}
}
// 改变自己的值、通过父组件传递
accumulation = () => {
const { brotherCallback } = this.props
this.setState({
mun:this.state.mun + 1
}, () => {
brotherCallback(this.state.mun)
})
}
render() {
const { mun } = this.props
return (
<>
<h2>我是Child2组件:</h2>
<button onClick={ this.accumulation }>点击我 改变[Child1]组件的值</button>
</>
)
}
}
// 父组件
class Parent extends Component {
constructor(props) {
super(props)
// 通过ref控制
this.ChildRef = createRef()
this.state = {
brother:0
}
}
// 利用中介的方式
brotherCallback = (mun) => {
this.setState({
brother:mun
})
}
render() {
const { brother } = this.state
return (
<>
<h2>我是父组件</h2>
<hr />
<Child1 brother={brother} />
<hr />
<Child2 brotherCallback={this.brotherCallback}/>
</>
)
}
}
export default Parent
Hooks 组件:
import React, { useState,useEffect } from 'react'
const Child1 = (props) => {
const { brother } = props;
return (
<>
<h2>我是Child1组件:{brother}</h2>
</>
)
}
const Child2 = (props) => {
const [mun, setMun] = useState(0)
const { brotherCallback } = props
// 改变自己的值、通过父组件传递
const accumulation = () => {
setMun((value) => {
return value + 1
})
}
useEffect(() => {
if(mun !== 0 ) {
brotherCallback(mun)
}
}, [mun])
return (
<>
<h2>我是Child2组件:</h2>
<button onClick={accumulation }>点击我 改变[Child1]组件的值</button>
</>
)
}
const Parent = () => {
const [brother,setBrother] = useState(0);
return (
<>
<h2>我是父组件</h2>
<hr />
<Child1 brother={brother} />
<hr />
<Child2 brotherCallback={(mun) => setBrother(mun)}/>
</>
)
}
export default Parent
(爷孙组件)嵌套组件:
嵌套组件其实也可以采用父子组件的传递方式、但是如果层级过深显然不好维护,所以这里推荐采用Context
进行维护数据源的状态
详情请看:Context文档描述的很详细。
Class 组件:
import React, { Component, createRef } from 'react'
// 后期可以把他单独放在一个js文件维护
const ThemeContext = React.createContext();
// 孙子组件
class Grandson extends Component{
constructor(props) {
super(props)
this.state = {}
}
static contextType = ThemeContext;
shouting = () => {
const { grandsonCallback } = this.context
grandsonCallback({
massge:"我累了、毁灭吧"
})
}
render() {
const { parentObj } = this.context
return (
<>
<h2>我是孙子组件</h2>
<p>接收的值:{parentObj.name} 年龄{parentObj.age}岁</p>
<button onClick={this.shouting}>隔空喊话</button>
</>
)
}
}
// 儿子组件
class Child extends Component {
constructor(props) {
super(props)
this.state = {}
}
render() {
return (
<>
<h2>我是儿子组件</h2>
<hr />
<Grandson />
</>
)
}
}
// 父组件
class Parent extends Component {
constructor(props) {
super(props)
this.state = {
parentObj:{
name:"我是你爷爷",
age:88
},
// 接受孙子组件的数据
grandson:{}
}
}
grandsonCallback = (data) => {
this.setState({
grandson:data
})
}
render() {
const { parentObj, grandson } = this.state;
return (
<>
<h2>我是父组件</h2>
<p>{( grandson && grandson.massge ) ? grandson.massge : '' }</p>
<hr />
<ThemeContext.Provider value={ { parentObj, grandsonCallback: this.grandsonCallback } }>
<Child />
</ThemeContext.Provider>
</>
)
}
}
export default Parent
Hooks 组件:
import React, { useState, useContext } from 'react'
// 后期可以把他单独放在一个js文件维护
const ThemeContext = React.createContext();
const Grandson = () => {
const context = useContext(ThemeContext)
const { parentObj, grandsonCallback } = context;
const shouting = () => {
grandsonCallback({
massge:"我累了、毁灭吧"
})
}
return (
<>
<h2>我是孙子组件</h2>
<p>接收的值:{parentObj.name} 年龄{parentObj.age}岁</p>
<button onClick={shouting}>隔空喊话</button>
</>
)
}
const Child = () => {
return (
<>
<h2>我是儿子组件</h2>
<hr />
<Grandson />
</>
)
}
const Parent = () =>{
const [grandson, setGrandson] = useState({});
const [parentObj, setParentObj] = useState(
{
name:"我是你爷爷",
age:88
});
const grandsonCallback = (data) => {
setGrandson(data)
}
return (
<>
<h2>我是父组件</h2>
<p>{( grandson && grandson.massge ) ? grandson.massge : '' }</p>
<hr />
<ThemeContext.Provider value={ { parentObj, grandsonCallback } }>
<Child />
</ThemeContext.Provider>
</>
)
}
export default Parent
最后
其实在常见的组件通信中,以上的方式绰绰有余、但是面对复杂的大型项目中还是推荐采用redux这样的状态存储对象来统一管理、如果redux灵活性不高,这里也推荐采用dva进行管理、就像它的特性一样:快速上手、易学易用。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。