持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第2天,点击查看活动详情
前言
本文主要总结父子组件在属性与方法之间传递,包括通过props传递属性与方法,以及通过ref获取组件实例方法获取组件属性与方法。其次我们也要关注中间人模式、发布-订阅模式、生产者与消费者模式在非父子组件通信中的应用。
1.父子组件通信
(1)通过props进行子父通信 (传递数据(父传子)与传递方法(子传父))
传递数据父传子使用props属性传递(参考props属性) 传递方法子传父,将方法当做属性传入子组件,子组件通过props获取该方法,并执行及传递参数 在父组件中: 定义方法,并使用props方式将方法传入子组件
import React, {Component} from 'react';
import Children from "./children";
class Parent extends Component {
render() {
return (
<div>
<span> 父组件</span>
<Children events={this.handleEvent}/>
</div>
);
}
handleEvent(e){
console.log(e)
}
}
export default Parent;
在子组件中:
在props中获取父组件传入的方法,注意方法名要与父组件传入相同。
import React, {Component} from 'react';
class Children extends Component {
render() {
return (
<div>
<button onClick={()=>{
this.props.events('子组件触发父组件方法')
}}>点击</button>
<span>子组件</span>
</div>
);
}
}
export default Children;
(2)ref标记(父组件拿到子组件的引用,从而调用子组件的方法)
子组件内部维护状态及方法,父组件通过ref获取子组件状态及方法并执行,同vue相似,都是通过ref获取组件实例,从而获取子组件挂载在实例上的方法与属性。 在父组件中: ref绑定子组件,从而获取子组件内的状态与方法。
import React, {Component} from 'react';
import Children from "./children";
class Parent extends Component {
inputref=React.createRef()
render() {
return (
<div>
<span> 父组件</span>
<Children ref={this.inputref} />
<button onClick={()=>{
console.log(this.inputref.current.state.value)
}}>获取</button>
<button onClick={()=>{
this.inputref.current.clear()
}}>重置</button>
</div>
);
}
}
export default Parent;
在子组件中:
import React, {Component} from 'react';
class Children extends Component {
state={
value:''
}
clear(){
this.setState({
value:''
})
}
render() {
return (
<div>
<input value={this.state.value} onChange={(e)=>{
this.setState({
value:e.target.value
})
}}/>
<span>子组件</span>
</div>
);
}
}
export default Children;
tip:在父组件中清除子组件的input输入框的value值,this.$refs.form.reset()
2.非父子组件通信
(1)状态提升(中间人模式)
所谓中间人模式其实在Angular中比较常用,当设计组件时,我们的组件应该是内聚的,应该不依赖外部已经存在的组件,要实现这种松耦合的组件Angular中常使用中间人模式,将状态提升。
而在JavaScript中我认为更为准确应当是中介者模式,中介者模式可以解除对象与对象之间的紧耦合关系,当使用中介者模式时,对象与对象之间的通信都是通过中介者来完成,而不是相互引用。
当一个对象状态发生改变时,只需要通知中介者即可,而不需要通知互相引用的对象,这样就从多对多的关系变成了一对多的关系。
React中的状态提升,就是将多个组件需要共享的状态提升到他们最近的父组件上,在父组件上改变这个状态,然后通过props分发给子组件。
(2)发布-订阅模式
发布-订阅模式又叫做观察者模式,是一种一对多的关系,当对象状态发生改变时,将会通知所有的观察者,在JavaScript中,常用事件模型来替代,该模式广泛应用于异步编程,只需要订阅相关状态,我们并不需要知道异步执行过程中的事情,在异步方法执行完毕后获取结果即可。
具体实现:
发布-订阅模式,订阅者将回调函数注册到公众平台,发布者发布时,将回调函数取出执行,并返回发布内容。
import React, {Component} from 'react';
class Bus extends Component {
render() {
return (
<div>
发布订阅模式
</div>
);
}
}
const bus={
list:[],
content:'测试数据,订阅者',
subscribe(callback){
this.list.push(callback)
},
publish() {
this.list.forEach((callback,index)=>{
callback(`${this.content}${index+1}号`)
})
}
}
bus.subscribe((e)=>{
console.log(e)
})
bus.subscribe((e)=>{
console.log(e)
})
bus.publish()
export default Bus;
(3)context状态树传参(生产者、消费者模式)
context状态树传参其实是生产者、消费者模式,生产者是指产生数据的模块,消费者是指处理数据的模块,并且生产者与消费者之间需要中介作为缓冲区来缓存数据,这样生产者与消费者之间就不用产生依赖,降低耦合度。
a.先定义全局context对象
export const GlobalContext=React.createContext()
b.父组件引入GlobalContext,并使用GlobalContext.Provider(生产者)
import React from 'react';
import ReactDOM from 'react-dom/client';
import Bus from './day2/bus'
const root = ReactDOM.createRoot(document.getElementById('root'));
export const GlobalContext=React.createContext()
root.render(
// <React.StrictMode>
<GlobalContext.Provider value={
{
name:'全局context测试',
}
}>
<Bus />
</GlobalContext.Provider>
);
c.子组件引入GlobalContext,并使用GlobalContext.Consumer(消费者)
import React, {Component} from 'react';
import {GlobalContext} from '../index'
class Bus extends Component {
render() {
return (
<GlobalContext.Consumer>
{
(value)=>{
return <div>{value.name}</div>
}
}
</GlobalContext.Consumer>
)
}
}
export default Bus;