前言
用react写项目时,组件间通信是必须要掌握的,但实现组件通信有很多种方法,所以要根据项目实际情况,使用最佳的方法,才能令你,事半功倍
下面有6种组件间通讯方法,代码中都写了注释哦,文章总结有代码下载链接
目录
一、父传子
子组件通过this.props接收父组件传来的数据
最佳使用场景:数据简单,状态单一,数据只涉及在父子组件中使用
1、父组件
import React, { Component } from 'react'
import Child from './child'
class Demo1 extends Component {
state = {
userInfo: {
name: 'A.Liang',
age: '22',
},
}
render() {
const { userInfo } = this.state
return (
<div>
demo1
<Child userInfo={userInfo} />
</div>
)
}
}
export default Demo1
2、子组件
import React, { Component } from 'react'
class Child extends Component {
render() {
const { userInfo = {} } = this.props
const { name = '', age = '' } = userInfo
return (
<div>
child
<div>
<label>姓名:</label>
<span>{name}</span>
</div>
<div>
<label>年龄:</label>
<span>{age}</span>
</div>
</div>
)
}
}
export default Child
二、子传父
子组件通过 回调函数 向父组件传递数据。父组件将自己的某个方法传递给子组件,子组件通过this.props接收到父组件的方法后进行调用。
最佳使用场景:数据简单,状态单一,数据只涉及在父子组件中使用
1、父组件
import Child from './child'
class Demo2 extends Component {
state = {
name: 'A.Liang',
age: '22',
}
render() {
const { name = '', age = '' } = this.state
return (
<div>
Demo2
<div>
<label>姓名:</label>
<span>{name}</span>
</div>
<div>
<label>年龄:</label>
<span>{age}</span>
</div>
<Child handleSaveData={obj => this.setState(obj)} />
</div>
)
}
}
export default Demo2
2、子组件
import React, { Component } from 'react'
class Child extends Component {
componentDidMount() {
console.log('child==>', this.props)
}
render() {
const { handleSaveData } = this.props
return (
<div>
child
{handleSaveData && (
<button onClick={() => handleSaveData({ name: '阿良' })}>
修改姓名
</button>
)}
</div>
)
}
}
export default Child
三、ref
父组件通过 ref 获取到子组件的实例或者元素,调用子组件的方法进行数据传递
最佳使用场景:需使用子组件的方法、数据时;尽量不使用,用多了可读性变差
1、父组件
import React, { Component } from 'react'
import Child from './child'
class Demo6 extends Component {
constructor(props) {
super(props)
this.state = {}
this.childRef = React.createRef()
}
changeName = () => {
console.log(`修改姓名`)
const childRef = this.childRef
childRef.current.changeName()
console.log(`childRef==>`, childRef)
}
render() {
return (
<div>
<p>Demo6</p>
<button onClick={this.changeName}>修改姓名</button>
<hr />
<Child ref={this.childRef} />
</div>
)
}
}
export default Demo6
2、子组件
import React, { Component } from 'react'
class Child extends Component {
state = {
userInfo: {
name: 'A.Liang',
age: '22',
},
}
changeName = () => {
console.log(`修改姓名`)
const { userInfo } = this.state
userInfo.name = '阿良'
this.setState({ userInfo })
}
resetName = () => {
console.log('还原名字')
const { userInfo } = this.state
userInfo.name = 'A.Liang'
this.setState({ userInfo })
}
render() {
const { userInfo = {} } = this.state
const { name = '', age = '' } = userInfo
return (
<div>
child
<div>
<label>姓名:</label>
<span>{name}</span>
</div>
<div>
<label>年龄:</label>
<span>{age}</span>
</div>
<button onClick={this.resetName}>还原名字</button>
</div>
)
}
}
export default Child
四、Context
react 中数据是通过 props 属性自上而下(由父及子)进行传递的,但这种做法对于多层级父子关系的组件传值是极其繁琐的。react 提供了context api 来实现在组件之间共享此类值的方式,而不必显式地通过组件树的逐层传递 props,使用 Context 做组件间的通讯会使得组件的复用性变差
最佳使用场景:组件不多,管理的状态、数据简单,项目中没有redux
1、父组件
import React, { Component } from 'react'
import Child from './child'
import { MyContext } from './myContext.js'
class Demo4 extends Component {
state = {
userInfo: {
name: 'A.Liang',
age: 23,
},
}
render() {
return (
<MyContext.Provider value={this.state.userInfo}>
Demo4
<Child />
</MyContext.Provider>
)
}
}
export default Demo4
2、context.js
import React from 'react'
export const MyContext = React.createContext({
data: 'default data',
})
3、子组件(child1)
import React, { Component } from 'react'
import Son from './son.js'
import { MyContext } from './myContext.js'
class Child extends Component {
// 指定 contextType 读取 my的context对象
// 这样写的话,可以不用.Consumer去获取里面的数据
static contextType = MyContext
componentDidMount() {
// 查看MyContext里的数据
console.log('context==>', this.context)
}
render() {
return (
<div>
Child
<Son />
</div>
)
}
}
4、子孙组件(son)
import React, { Component } from 'react'
import { MyContext } from './myContext.js'
class Son extends Component {
render() {
return (
<MyContext.Consumer>
{(userInfo = {}) => {
const { name = '', age = '' } = userInfo
console.log('userInfo==>', userInfo)
return (
<div>
son
<div>
<label>姓名:</label>
<span>{name}</span>
</div>
<div>
<label>年龄:</label>
<span>{age}</span>
</div>
</div>
)
}}
</MyContext.Consumer>
)
}
}
export default Son
五、event bus
利用中央事件总线,event bus可以适用于任何情况的组件通信,在项目规模不大的情况下,完全可以使用中央事件总线event bus的方式
最佳使用场景:组件不多,管理的状态、数据简单、状态(数据)没变化依旧触发时,bus且项目中没有redux
1、父组件
import React, { Component } from 'react'
import Child from './child'
import Child2 from './child2.js'
class Demo3 extends Component {
componentDidMount() {
console.log('Demo3==>', this.props)
}
render() {
return (
<div>
Demo3
<Child />
<Child2 />
</div>
)
}
}
export default Demo3
2、bus.js
import { EventEmitter } from 'events'
var bus = new EventEmitter() //注册一个组件
export { bus } //导出
3、子组件(child1)
import React, { Component } from 'react'
import { bus } from './bus'
class Child extends Component {
//传值的触发函数
sentToB = () => {
bus.emit('eventbus', {
name: '阿良',
age: 18,
})
}
render() {
return (
<div>
child
<button onClick={this.sentToB}>请点击我触发sentToB进行传值</button>
</div>
)
}
}
export default Child
4、子组件(child2)
import React, { Component } from 'react'
import { bus } from './bus'
class Child2 extends Component {
constructor(props) {
super(props)
this.state = {
name: 'A.Liang',
age: 23,
}
}
componentDidMount() {
// bus.on监听事件 将传递的值绑定到state
// 监听event事件,获得emit传递的参数,触发时调用callback函数
bus.on('eventbus', data => {
this.setState(data)
})
}
render() {
const { name = '', age = '' } = this.state
return (
<div>
Child2
<div>
<label>姓名:</label>
<span>{name}</span>
</div>
<div>
<label>年龄:</label>
<span>{age}</span>
</div>
</div>
)
}
}
export default Child2
六、Redux
集中式状态管理模式,Redux 的状态管理存储是响应式的,可以集中式存储管理应用的所有状态
推荐使用场景:如果项目比较复杂、模块比较很多的情况,推荐使用 Redux 来做组件间的通信。
1、父组件
import React, { Component } from 'react'
import Child from './child'
import Child2 from './child2.js'
class Demo3 extends Component {
render() {
return (
<div>
Demo5
<Child />
<hr />
<Child2 />
</div>
)
}
}
export default Demo3
2、store的配置
2.1、reducer.js(第一步:定义计算规则,即 reducer)
const initialState = {
cityName: '杭州',
}
// 第一步:定义计算规则,即 reducer
const userinfo = (state = initialState, action) => {
switch (action.type) {
// 修改城市
case 'UPDATE_CITYNAME':
return action.data
default:
return state
}
}
export default userinfo
2.2、store/configureStore.js(根据计算规则生成 store)
import { createStore } from 'redux'
import rootReducer from '../reducers'
export default function configureStore(initialState) {
const store = createStore(
rootReducer,
initialState,
// 触发 redux-devtools
window.devToolsExtension ? window.devToolsExtension() : undefined
)
return store
}
2.3、index.js(入口文件引入、挂载store)
import React from 'react'
import ReactDOM from 'react-dom'
import { Provider } from 'react-redux'
import App from './containers/App'
import configureStore from './store/configureStore'
const store = configureStore()
ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>,
document.getElementById('root')
)
2.4、action/userinfo.js(触发数据变化的actions)
export const updateCityName = data => ({
type: 'UPDATE_CITYNAME',
data,
})
3、子组件(child1)
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import * as userInfoActions from '../../actions/userinfo'
class Child1 extends Component {
state = {}
componentDidMount() {
const { userInfoActions } = this.props
console.log('Child1-userInfoActions :>> ', userInfoActions)
}
// 修改城市
handleChangeCity = () => {
const { updateCityName } = this.props.userInfoActions
updateCityName && updateCityName({ cityName: '上海' })
}
render() {
const { cityName } = this.props.userinfo
return (
<div>
<div>Child1:{cityName}</div>
<button onClick={this.handleChangeCity}>改变城市为'上海'</button>
</div>
)
}
}
const mapStateToProps = state => ({
userinfo: state.userinfo,
})
const mapDispatchToProps = dispatch => ({
userInfoActions: bindActionCreators(userInfoActions, dispatch),
})
export default connect(mapStateToProps, mapDispatchToProps)(Child1)
4、子组件(child2)
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import * as userInfoActions from '../../actions/userinfo'
class Child2 extends Component {
state = {}
componentDidMount() {
const { userInfoActions } = this.props
console.log('Child2-userInfoActions :>> ', userInfoActions)
}
// 修改城市
handleChangeCity = () => {
const { updateCityName } = this.props.userInfoActions
updateCityName && updateCityName({ cityName: '杭州' })
}
render() {
const { cityName } = this.props.userinfo
return (
<div>
<div>Child2:{cityName}</div>
<button onClick={this.handleChangeCity}>改变城市为'杭州'</button>
</div>
)
}
}
const mapStateToProps = state => ({
userinfo: state.userinfo,
})
const mapDispatchToProps = dispatch => ({
userInfoActions: bindActionCreators(userInfoActions, dispatch),
})
export default connect(mapStateToProps, mapDispatchToProps)(Child2)
七、总结
1、父子通信:
①父传子
②子传父
③ref
④context
⑤event bus
⑥redux
2、跨组件通信
①event bus
②context
③redux
代码下载:https://gitee.com/staraliang/react17-app/tree/p-comp-by-value
你可能感兴趣的文章: