简单手写实现React类组件的state批量更新

本文的目标是,手写实现React类组件的 state 批量更新。

TL;DR

  • 拆分setState逻辑,每一个类组件绑定一个Updater实例,Updater专门处理state的逻辑,以及什么时候更新
  • 增加pendingStates,这样state更新的时候,辅助批量更新
  • 增加updateQueue来控制批量更新,这里用了观察者模式,订阅更新
  • 处理事件逻辑,切片事件函数,执行前增加flag的开始,执行后开始更新和重置flag。

准备工作

先将index.js的点击事件略微修改

import React from './source/react';
import ReactDOM from './source/react-dom';
// import React from 'react';
// import ReactDOM from 'react-dom';

class Count extends React.Component {constructor(props) {super(props);this.state = { number: 1 };}handleClick = () => {this.setState({ number: this.state.number + 1 });// {number:1}console.log('第一次setState', this.state);this.setState({ number: this.state.number + 1 });// {number:1}console.log('第二次setState', this.state);setTimeout(() => {this.setState({ number: this.state.number + 1 });// {number:3}console.log('setTimeout第一次setState', this.state);this.setState({ number: this.state.number + 1 });// {number:4}console.log('setTimeout第一次setState', this.state);});};render() {return (
{this.state.number}
);} } const reactElement = ; ReactDOM.render(reactElement, document.getElementById('root'));

点击之后,看控制台:

简单手写实现React类组件的state批量更新_第1张图片

state 怎么更新的?同步?异步?

state 更新一般发生的情况:

1.请求
2.交互事件

React17 之前,触发事件的时候,同一事件里面的 setState 会被攒在一起,然后更新。 而事件之外的,每次 setState,state 就会当场更新。

setTimeout 和请求 都是在事件之外的,所以会当场更新。

核心原理是,事件函数被处理了,同一事件函数,里面的 setState 被放到集合里,事件函数结束的时候一起更新。而其他的并未做处理。

分析 state 的批量更新

1.setState 的时候,之前直接更新,设置一个 flag,才判断是是更新还是将修改状态暂存
2.事件触发,事件开始的时候,设置一个 flag,setState 都放进集合里;事件结束的时候 flag 重置,更新 state

实现

1.增加 Update 类,将 setState 的逻辑拆分

setState主要是增加状态,而状态是否真的增加、是否更新组件等需要额外的逻辑,考虑到逻辑略复杂,所以抽象到一个类Updater里,每个类组件关联一个Updater实例,用来管理state

class Updater{constructor(componentInstance){this.componentInstance = componentInstance}addState(partialState){// 刚开始是状态增加,就立马更新const {state} = this.componentInstancethis.componentInstance.state = { ...state, ...partialState };this.componentInstance.updateDom()}

}setState(partialState) {// 每次setState之后,让updater去处理逻辑,这边只是单纯的加状态this.updater.addState(partialState)} 

2.增加是否批量更新的逻辑

这里,为了后期方便,运用观察者模式,利用一个对象来控制批量更新的逻辑。 因为增加批量更新的逻辑,所以addState原逻辑简单拆分,更新逻辑分离出去,且因为 state 可能会多次累加,所以这边也增加一个getState方法,能计算到新的state

let updateQueue = {isBatchUpdating: false,updaters: new Set(),// 批量更新,目前是只有在事件结束的时候才会调用batchUpdate() {// 挨个更新for (let update of updateQueue.updaters) {update.updateComponent();}// 重置updatersupdateQueue.updaters.clear();// 重置isBatchUpdatingupdateQueue.isBatchUpdating = false;},
};

class Updater {// ...addState(partialState) {this.pendingStates.push(partialState);// 是批量更新的话,将本实例加入到updateQueueif (updateQueue.isBatchUpdating) {updateQueue.updaters.add(this);return;}// 如果不是等着批量更新,那直接更新就好this.updateComponent();}updateComponent() {// 新状态的获取这边用一个方法计算出来,逻辑清晰this.componentInstance.state = this.getState();this.componentInstance.updateDom();}getState() {// 根据pendingStates得到新的statelet { state } = this.componentInstance;const { pendingStates } = this;for (let i = 0; i < pendingStates.length; i++) {state = { ...state, ...pendingStates[i] };}pendingStates.length = 0;return state;}
} 

3.事件绑定的时候,加上批量更新的逻辑

绑定事件的时候,将原事件稍微切片下,前后方都加上批量更新的逻辑

  • 设置批量更新的 flag 是 true
  • 事件运行
  • 运行结束,执行批量更新
function updateProps(DOM, props) {// ...if (/on[A-Z]+/.test(key)) {const eventFn = props[key];DOM[key.toLowerCase()] = (...args) => {updateQueue.isBatchUpdating = true;eventFn(...args);// batchUpdate内部有重置updateQueue的逻辑updateQueue.batchUpdate();};}// ...
} 

老规矩,index.js打开自己文件的路径

正常运行,✌️~~~

最后

整理了75个JS高频面试题,并给出了答案和解析,基本上可以保证你能应付面试官关于JS的提问。



有需要的小伙伴,可以点击下方卡片领取,无偿分享

你可能感兴趣的:(react.js,javascript,前端)