Read the instructions

  • The preact version referenced for this article is 10.5.13
  • The article will omit most of the logic, such as hydrating, context, isSvg, etc. So be careful if any big shots come in.
  • Abbreviated version code

setState

  • SetState: setState(updater, callback) : setState(updater, callback) : setState(updater, callback);
    • Get the latest state of the component itself
    • If update is a function, perform update to get the modified state and merge it with the old state. If update is an object, merge into the old state.
    • Save the callback function to the component’s own _renderCallbacks,
Component.prototype.setState = function(update, callback) { let s; If (this._nextState! = this._nextstate! = null && this._nextState ! == this.state) { s = this._nextState; } else { s = this._nextState = assign({}, this.state); } // If (typeof update == 'function') {update = update(assign({}, s), this.props);} // If (typeof update == 'function') {update = update(assign({}, s), this.props); If (update) {assign(s, update); // assign(s, update); } if (update == null) return; Rendercallbacks if (this._vnode) {if (callback) this._rendercallbacks. Push (callback); enqueueRender(this); }};Copy the code

enqueueRender

  • C. _dirty=true Indicates whether components are being updated.
    • C._dirty = true on first render initialization. After render: c._dirty = false.
    • SetState checks to see if the component is in the update state, instead of entering the update queue to delay the update, and marks the component as being in the update state.
  • Preact Asynchronous update: Place the update function to be executed at promiose.then
  • RerenderQueue is sorted based on ascending _depth, with updates starting from child components and going from bottom to top.
    • For example, the child setState then passes the click function to the parent, which also executes setState.
// Store components that need to be updated let rerenderQueue = []; // Const defer = typeof Promise == 'function'? Promise.prototype.then.bind(Promise.resolve()) : setTimeout; export function enqueueRender(c) { if ( (! c._dirty && (c._dirty = true) && rerenderQueue.push(c) && ! process._rerenderCount++) ) { defer(process); Function process() {let queue; while ((process._rerenderCount = rerenderQueue.length)) { queue = rerenderQueue.sort((a, b) => a._vnode._depth - b._vnode._depth); rerenderQueue = []; queue.some(c => { if (c._dirty) renderComponent(c); }); Process. _rerenderCount = 0;Copy the code

renderComponent

  • Call the component’s diff to update. The commitRoot then executes the life cycle saved in the commitQueue
function renderComponent(component) { let vnode = component._vnode, oldDom = vnode._dom, parentDom = component._parentDom; if (parentDom) { let commitQueue = []; const oldVNode = assign({}, vnode); oldVNode._original = vnode._original + 1; diff( parentDom, vnode, oldVNode,, commitQueue, oldDom == null ? getDomSibling(vnode) : oldDom, ); commitRoot(commitQueue, vnode); if (vnode._dom ! = oldDom) { updateParentDomPointers(vnode); }}}Copy the code

forceUpdate

Component.prototype.forceUpdate = function(callback) { if (this._vnode) { this._force = true; if (callback) this._renderCallbacks.push(callback); enqueueRender(this); }};Copy the code