Preact是React的輕量級實現,是React比較好的替代者之一,有著體積小的優點,當然與React之間一定會存在實現上的差異,本文介紹了在setState 方面的差異之處。
首先來分析下React以及Preact在setState部分的具體實作。
(太長不看想偷懶,可以直接下翻看結論)
關鍵程式碼:
##setState 階段:// ReactUpdateQueue.jsenqueueSetState: function(publicInstance, partialState) { ... var queue = internalInstance._pendingStateQueue || (internalInstance._pendingStateQueue = []); queue.push(partialState); enqueueUpdate(internalInstance);}可以看到React在setState 的時候不會做任何處理,會把變更直接放到一個專門處理state 的佇列裡供元件更新時使用。 更新階段:
// ReactCompositeComponent.jsupdateComponent: function( transaction, prevParentElement, nextParentElement, prevUnmaskedContext, nextUnmaskedContext,) { var inst = this._instance; ... var willReceive = false; var nextContext; if (this._context === nextUnmaskedContext) { nextContext = inst.context; } else { nextContext = this._processContext(nextUnmaskedContext); willReceive = true; } var prevProps = prevParentElement.props; var nextProps = nextParentElement.props; if (prevParentElement !== nextParentElement) { willReceive = true; } if (willReceive && inst.componentWillReceiveProps) { ... inst.componentWillReceiveProps(nextProps, nextContext); } // 在此处才计算 nextState var nextState = this._processPendingState(nextProps, nextContext); // 此处传入了 nextProps var shouldUpdate = true; if (!this._pendingForceUpdate) { if (inst.shouldComponentUpdate) { ... shouldUpdate = inst.shouldComponentUpdate( nextProps, nextState, nextContext, ); } else { if (this._compositeType === CompositeTypes.PureClass) { // 敲黑板,知识点 —— 如果你的组件没实现shouldComponentUpdate,那么把React.Component 换成 React.PureComponent 可以获得基础版优化,提高性能。 shouldUpdate = !shallowEqual(prevProps, nextProps) || !shallowEqual(inst.state, nextState); // 浅比较,可以抄去自己改成属性黑/白名单版 } } } ...}// ReactCompositeComponent.js_processPendingState: function(props, context) { // props: nextProps var inst = this._instance; var queue = this._pendingStateQueue; var replace = this._pendingReplaceState; this._pendingReplaceState = false; this._pendingStateQueue = null; if (!queue) { return inst.state; } if (replace && queue.length === 1) { return queue[0]; } var nextState = Object.assign({}, replace ? queue[0] : inst.state); for (var i = replace ? 1 : 0; i < queue.length; i++) { var partial = queue[i]; Object.assign( nextState, typeof partial === 'function' ? partial.call(inst, nextState, props, context) // nextProps : partial, ); } return nextState;}透過上面元件更新的流程程式碼可以看到:
// component.jssetState(state, callback) { let s = this.state; if (!this.prevState) this.prevState = extend({}, s); extend(s, typeof state==='function' ? state(s, this.props) : state); if (callback) (this._renderCallbacks = (this._renderCallbacks || [])).push(callback); enqueueRender(this);}實作的簡單粗暴,在setState 的時候就進行了合併,會立即改寫this.state,在第一次setState 時會保留state 狀態到prevState。由於是立即合併state,如果入參state是函數,props 將只是當前 this.props。 更新階段:
export function renderComponent(component, opts, mountAll, isChild) { ... previousProps = component.prevProps || props, previousState = component.prevState || state, previousContext = component.prevContext || context, ... // if updating if (isUpdate) { component.props = previousProps; component.state = previousState; component.context = previousContext; if (opts!==FORCE_RENDER && component.shouldComponentUpdate && component.shouldComponentUpdate(props, state, context) === false) { skip = true; } else if (component.componentWillUpdate) { component.componentWillUpdate(props, state, context); } component.props = props; component.state = state; component.context = context; } ...}在更新流程前提取了舊state,shouldComponentUpdate、componentWillUpdate 之後還原回新值,所以在shouldComponentUpdate 生命週期中, this.props 將取得的是prevProps,這裡與React 的邏輯並不一致。 劃重點相同點:
不會套用到 nextState,但可以直接操作傳入的 nextState。
但是,在更新元件的生命週期到 render 前(eg: shouldComponentUpdate), this.state 將會是 prevState。
以上是React與Preact中關於setState的區別的詳細內容。更多資訊請關注PHP中文網其他相關文章!