In ReactJS, why does `setState` behave differently when called synchronously?

后端 未结 6 711
南笙
南笙 2020-11-29 21:19

I am trying to understand the underlying cause for some somewhat \"magical\" behavior I am seeing that I cannot fully explain, and which is not apparent from reading the Rea

6条回答
  •  一向
    一向 (楼主)
    2020-11-29 22:12

    This is not exactly an answer, but one possible approach to mitigating the issue. It defines a wrapper for React inputs that manages value updates synchronously via a local state shim; and versions the outgoing values so that only the latest returned from asynchronous processing is ever applied.

    It's based on some work by Stephen Sugden (https://github.com/grncdr) which I updated for modern React and improved by versioning the values, which eliminates the race condition.

    It's not beautiful :)

    http://jsfiddle.net/yrmmbjm1/1/

    var AsyncInput = asyncInput('input');
    

    Here is how components need to use it:

    var AI = asyncInput('input');
    
    var Test = React.createClass({
        // the controlling component must track
        // the version
        change: function(e, i) {
          var v = e.target.value;
          setTimeout(function() {
            this.setState({v: v, i: i});
          }.bind(this), Math.floor(Math.random() * 100 + 50));
        },
        getInitialState: function() { return {v: ''}; },
        render: function() {
          {/* and pass it down to the controlled input, yuck */}
          return 
        }
    });
    React.render(, document.body);
    

    Another version that attempts to make the impact on the controlling component's code less obnoxious is here:

    http://jsfiddle.net/yrmmbjm1/4/

    That ends up looking like:

    var AI = asyncInput('input');
    
    var Test = React.createClass({
        // the controlling component must send versionedValues
        // back down to the input
        change: function(e) {
          var v = e.target.value;
          var f = e.valueFactory;
          setTimeout(function() {
            this.setState({v: f(v)});
          }.bind(this), Math.floor(Math.random() * 100 + 50));
        },
        getInitialState: function() { return {v: ''}; },
        render: function() {
          {/* and pass it down to the controlled input, yuck */}
          return 
        }
    });
    React.render(, document.body);
    

    ¯\_(ツ)_/¯

提交回复
热议问题