React method of setState

React setState the method, two parameters may be received, one object / function [must], a callback method is not necessarily] [callback

This is part of the source code setState

    Component.prototype.setState = function (partialState, callback) {
      (function () {
        if (!(typeof partialState === 'object' || typeof partialState === 'function' || partialState == null)) {
          {
            throw ReactError(Error('setState(...): takes an object of state variables to update or a function which returns an object of state variables.'));
          }
        }
      })();

      this.updater.enqueueSetState(this, partialState, callback, 'setState');
    };

According to the official version of the document, setState there are three things to note:

First, do not directly modify the State

Directly modify the state will not re-rendering components, we can be a test

import React from 'react';
export default class C1 extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      counter: 1
    };
  }
  handle() {
    this.state.counter = 2;
  }
  componentDidUpdate() {
    console.log('C1组件更新完毕 componentDidUpdate');
  }
  render() {
    console.log('C1子组件render');
    return (
      <div>
        <p>C1组件</p>
        {this.state.counter}
        <button
          type="button"
          onClick={() => {
            this.handle();
          }}
        >
          更新界面
        </button>
      </div>
    );
  }
}

The result is certainly not effective, not only has no effect, in the time saved will be prompted to use setState

Two, State updates will be merged

This is also very simple, setState method will only update the keys inside the parameter object methods, Object.assign static methods similar function for ES6

const target = { a: 1, b: 2 };
const source = { b: 3, c: 4 };
const returnedTarget = Object.assign(target, source);
console.log(target);// { a: 1, b: 3, c: 4 }
console.log(returnedTarget);// { a: 1, b: 3, c: 4 }

Three, State of the update may be asynchronous

What does this sentence mean? I pondered for a long time ~

For performance reasons, React might put more setState () call to merge into a single call.

example

import React from 'react';
export default class C1 extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      counter: 1
    };
  }
  handle() {
    this.setState({
      counter: this.state.counter + 1
    });
    this.setState({
      counter: this.state.counter + 2
    });
  }
  componentDidUpdate() {
    console.log('C1组件更新完毕 componentDidUpdate');
  }
  render() {
    console.log('C1子组件render');
    return (
      <div>
        <p>C1组件</p>
        {this.state.counter}
        <button
          type="button"
          onClick={() => {
            this.handle();
          }}
        >
          更新界面
        </button>
      </div>
    );
  }
}

After clicking the update button interface, counter display interface or 3, which is why? The reason is that the above sentence, for performance reasons, React might put more setState () call to merge into a single call.

We all know that consuming DOM rendering performance, so React To increase overall performance, in the same period a rendering of setState merge, so the above example, react just look for the rendering of the current period of the last setState, it is equal to 3 + 1.

When will it react will not be merged with a rendering cycle setState inside it? This involves another use of setState:

import React from 'react';
export default class C1 extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      counter: 1
    };
  }
  handle() {
    this.setState(state => ({
      counter: state.counter + 1
    }));
    this.setState(state => ({
      counter: state.counter + 1
    }));
  }
  componentDidUpdate() {
    console.log('C1组件更新完毕 componentDidUpdate');
  }
  render() {
    return (
      <div>
        <p>C1组件</p>
        {this.state.counter}
        <button
          type="button"
          onClick={() => {
            this.handle();
          }}
        >
          更新界面
        </button>
      </div>
    );
  }
}

After clicking the button counter update interface rendered as 3, setState can also pass a function as the first argument

this.setState((state,props,context)=>({
    xx:state.xx+?
}))

Function which passed two parameters, namely the last update of the current state and the props, so you can update it so that this time state.counter get the latest value by state.counter when calling the method setState second.

So by state parameters property changes, the merger will not be processed, they will be treated if it is merged with the operation mode, then the function this.state inside, because the value of this.state which is not the latest . Why do you say that? We can verify through an example.

import React from 'react';
export default class C1 extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      counter: 1
    };
  }
  handle() {
    // this.setState(state => ({
    //   counter: state.counter + 1
    // }));
    this.setState({
      counter: this.state.counter + 1
    });
    console.log('handle执行时的counter',this.state.counter);
  }
  componentDidUpdate() {
    console.log('C1组件更新完毕 componentDidUpdate');
    console.log('更新完毕的counter',this.state.counter);
  }
  render() {
    console.log('render的counter',this.state.counter);
    return (
      <div>
        <p>C1组件</p>
        {this.state.counter}
        <button
          type="button"
          onClick={() => {
            this.handle();
          }}
        >
          更新界面
        </button>
      </div>
    );
  }
}

After clicking updated interface

We can see that the initial counter is 1, the handle when this.state.counter after setState, State and did not merge into this subject to the above , the value has not changed until after render execution, after rendering the page, It was changed. Of course, if you change that part of the above comments code assignment, then, will happen.

We can find this comment in the source code

* When a function is provided to setState, it will be called at some point in
* the future (not synchronously). It will be called with the up to date
* component arguments (state, props, context). These values can be different
* from this.* because your function may be called after receiveProps but before
* shouldComponentUpdate, and this new state, props, and context will not yet be
* assigned to this.

This comment explains a start appearing, modify counter by the way, no matter how this.state.counter only recognize the last setState problem from another angle.

Published 32 original articles · won praise 22 · views 40000 +

Guess you like

Origin blog.csdn.net/qq_34551390/article/details/104313759