githubreact
// react-dom.js function updateDOMAttr(dom, props) { for (let key in props) { if (key === "children") { continue; } if (key === "style") { for (let attr in props[key]) { dom.style[attr] = props[key][attr]; } } else if (key.startsWith("on")) { // onClick => onclick dom[key.toLocaleLowerCase()] = newProps[key] } else { dom[key] = props[key]; } } }
githubgit
this.setState()
時,實際調用 Component 類的 setState
addState()
,this.pendingStates = []
getState()
updateComponent()
forceUpdate()
強制更新視圖,將虛擬 dom 轉化爲真實 dom,掛載到視圖// Component.js class Updater { constructor(classInstance) { // 類組件實例 this.classInstance = classInstance; // 收集狀態 this.pendingStates = []; } addState(partialState) { this.pendingStates.push(partialState); // 若是當前處於批量更新模式 updateQueen.isBatchingUpdate ? updateQueen.add(this) : this.updateComponent(); } updateComponent() { let { classInstance } = this; if (this.pendingStates.length > 0) { // 替換 state 爲最新的狀態 classInstance.state = this.getState(); // 強制視圖進行更新 classInstance.forceUpdate(); } } // 獲取最新的狀態 getState() { let { classInstance, pendingStates } = this; let { state } = classInstance; if (pendingStates.length > 0) { pendingStates.forEach((nextState) => { if (isFunction(nextState)) { nextState = nextState(state); } else { state = { ...state, ...nextState }; } }); pendingStates.length = 0; } return state; } }
// Component.js class Component { static isReactComponent = true; constructor(props) { this.props = props; this.state = {}; this.updater = new Updater(this); } setState(partialState) { this.updater.addState(partialState); } // 更新視圖 forceUpdate() { // 此時 renderVdom 已是更新後的虛擬 DOM(state已經更新) let renderVdom = this.render(); updateClassComponent(this, renderVdom); } } function updateClassComponent(classInstance, renderVdom) { let oldDOM = classInstance.dom; let newDOM = createDOM(renderVdom); oldDOM.parentNode.replaceChild(newDOM, oldDOM); classInstance.dom = newDOM; }
githubgithub
添加隊列函數 updateQueen
使用 add()
收集 updaters
並使用 batchUpdate()
更新(相似發佈訂閱)dom
修改 index.js 文件內容,手動改變 isBatchingUpdate
的值,並手動清空隊列更新(這裏有點 low )異步
// index.js class Counter extends React.Component { constructor(props) { super(props); this.state = { number: 0 }; } handleClick = () => { updateQueen.isBatchingUpdate = true; this.setState({ number: this.state.number + 1 }); console.log(this.state); setTimeout(() => { updateQueen.batchUpdate(); }); }; render() { return ( <div> <p>number:{this.state.number}</p> <button onClick={this.handleClick}>點擊</button> </div> ); } }
export const updateQueen = { updaters: [], isBatchingUpdate: false, add(updater) { this.updaters.push(updater); }, batchUpdate() { this.updaters.forEach((updater) => updater.updateComponent()); this.isBatchingUpdate = true; }, };