Home  >  Article  >  Web Front-end  >  The difference between setState in React and Preact

The difference between setState in React and Preact

一个新手
一个新手Original
2017-10-24 09:34:281942browse

Preact is a lightweight implementation of React and one of the better alternatives to React. It has the advantage of small size. Of course, there will be implementation differences between it and React. This article introduces the differences in setState. at.

Source code analysis

First, let’s analyze the specific implementation of the setState part of React and Preact.

(It’s too long and you want to be lazy, you can just scroll down and read the conclusion)

React

Key code:

setState stage:


// ReactUpdateQueue.jsenqueueSetState: function(publicInstance, partialState) {
  ...  var queue =
    internalInstance._pendingStateQueue ||
    (internalInstance._pendingStateQueue = []);
  queue.push(partialState);

  enqueueUpdate(internalInstance);}

You can see that React will not do any processing when setState, and will directly put the changes into a queue specifically for processing state for use when components are updated.

Update stage:


// 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 === &#39;function&#39;
        ? partial.call(inst, nextState, props, context) // nextProps
        : partial,
    );
  }

  return nextState;}

You can see through the process code of the above component update:

  • In updateComponent , nextState is calculated after componentWillReceiveProps, so setState in componentWillReceiveProps can take effect in the current update.

  • In _processPendingState, the state in the queue will be superimposed. If the modification is in function mode, the state parameter passed here is nextState, and the props are nextProps.

Preact

Key code:

setState Stage:


##

// component.jssetState(state, callback) {
  let s = this.state;
  if (!this.prevState) this.prevState = extend({}, s);
  extend(s, typeof state===&#39;function&#39; ? state(s, this.props) : state);
  if (callback) (this._renderCallbacks = (this._renderCallbacks || [])).push(callback);
  enqueueRender(this);}

Simple implementation Rough, the merge is done during setState, this.state will be rewritten immediately, and the state will be retained in prevState during the first setState. Since the state is merged immediately, if the input parameter state is a function, the props will be the current this.props.

Update phase:


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;
  }
  ...}

The old state is extracted before the update process, and shouldComponentUpdate and componentWillUpdate are restored back to the new value, so in the shouldComponentUpdate life cycle, What this.props will get is prevProps, which is inconsistent with the logic of React.

Emphasis

Same point:

  • setState in componentWillReceiveProps will be applied to nextState.

  • setState in shouldComponentUpdate will

    not be applied to nextState, but the incoming nextState can be directly manipulated.

Difference:

  • The value of setState under React will not take effect immediately, but will accumulate until componentWillReceiveProps, after which it will be merged. And provide it to subsequent life cycles. Under Preact, setState will be reflected immediately to this.state,

    But, before updating the component's life cycle to render (eg: shouldComponentUpdate), this.state will be prevState.

  • shouldComponentUpdate stage setState Although it will not affect the final state value, it will affect the value of this.state under Preact, such as this.state in componentWillUpdate later. In short, do not setState at this stage It’s useless anyway.

  • setState If you use a function to modify it, the props passed in under Preact will be prevProps, while in React it will be nextProps. Pay attention when settingState in componentWillReceiveProps.

Summary

If the project you write needs to be compatible with both React and Preact:

  • Do not use setState under React The state is not updated immediately before the same component update is executed. Pay attention to whether there is any influence between multiple setStates, and save the old values ​​manually if necessary.

  • During the component update life cycle, do not use setState except componentWillReceiveProps. The nextState life cycle is provided and nextState can be modified directly.

  • Try to avoid using the setState function modification method. When using it in componentWillReceiveProps, use prevProps(this.props) and nextProps in the life cycle.

p.s: The official version of antd-mobile 2.0 has been released. It is also compatible with react and preact. It is a lightweight, fast and easy-to-use mobile component library, waiting for you to use~ [Portal 】

The above is the detailed content of The difference between setState in React and Preact. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn