一、事件总线
这里的事件总线和vue中基本一个思路。
在React中可以通过第三方库来进行任意组件通信,安装:
npm install hy-event-store
使用:
1、在某个地方新建jsx文件对外暴露事件总线
// 创建事件总线
import {
HYEventBus } from 'hy-event-store';
const eventBus = new HYEventBus();
export default eventBus;
2、在需要接收值的组件中,在挂在完毕的生命周期函数中绑定事件和被触发时的回调,最好写上销毁的代码:
//事件的回调
getData(name,age) {
console.log(name,age,this);
this.setState({
name: name, age: age
})
}
//1.挂载完毕后绑定事件接收别的地方传过来的值
componentDidMount() {
eventBus.on('getData', this.getData.bind(this))
}
//3.销毁的时候解绑
componentWillUnmount() {
eventBus.off('getData', this.getData)
}
3、另一个组件触发,并传值
sendData() {
//2.某个组件中触发事件并传值
eventBus.emit('getData', 'zzy', 18)
}
render() {
return (
<div>
<h1>GrandSon组件</h1>
<button onClick={
() => this.sendData()}>点击传值给App</button>
</div>
)
}
二、关于setState的原理
开发中我们并不能直接通过修改state的值来让界面发生更新:
因为我们修改了state之后,希望React根据最新的State来重新渲染界面,但是这种方式的修改React并不知道数据发生了变化;
React并没有实现类似于Vue2中的Object.defineProperty
或者Vue3中的Proxy
的方式来通过数据劫持
监听数据的变化;
我们必须通过setState
来告知React数据已经发生了变化;
源码先简单lou一眼:
1. setState的三种使用方式
我们基于以下组件进行操作
export class Son extends React.Component {
constructor() {
super();
this.state = {
name: 'zzy',
age: 18,
}
}
changeName() {
this.setState(...)
}
render() {
return (
<div>
<h1>{
this.state.name}</h1>
<button onClick={
() => this.changeName()}>点击修改名字</button>
</div>
)
}
}
(1)基本使用
我们之前用的最多的就是直接传入一个配置对象,然后给state中数据重新赋值。这里的原理是借助了Object.assign(state, newState)
对state
和传入的对象进行合并,如果key
重复那么就进行值的覆盖,没改的继续保留
//1.基本使用,传入配置对象,不是覆盖原来的state,而是进行对象的合并
this.setState({
name: 'ht' //原理:对象的合并Object.assign(state, newState)
})
(2)传入一个回调
setState
的参数除了可以传配置对象外,还可以传入一个回调函数,通过return
一个对象,对象中包含我们要修改的值,也可以实现数据的更新和页面的重新渲染。
这个回调可以接收两个参数:state和props
,分别对应的是上一个修改状态
的state
和props
的值们。
注意是上一个修改状态!如果在一个回调中多次执行setState
更改数据,那么参数state保存的是上一个修改状态的值!如果不明白请看本节2.1.1部分
//2.传入一个回调,可以接收修改之前的state和props
this.setState((state,props) => {
console.log(state,props);
return {
name: 'ht' //这里也可以进行更改
}
})
(3)第一个参数是对象,第二个参数是回调
setState
是一个异步调用。
如果在setState
下面使用name
,我们会发现拿到的是原来的name
,这就证明了setState
是一个异步调用,那么如果我们想在数据变化后再基于数据进行一些操作怎么办?这时候可以传入第二个参数:一个回调函数,该回调函数执行的时机就是数据更新完且render调用完毕后
。
//3.setState是一个异步调用
//如果想等数据更新后做一些操作,可以传入第二个参数:回调
//第二个参数执行的时机就是数据更新完之后
this.setState({
name