setState回调未按预期工作

时间:2017-10-11 18:13:48

标签: javascript reactjs setstate

我有一个正在运行的应用程序,我正在尝试将状态设置为loading: true,同时我的应用程序进行提交调用,以便我可以显示加载屏幕。因为我想确保在进行加载调用之前设置状态,所以我使用了回调。但是,我没有看到我的加载更新与下面的代码:

submitSecurityAnswer = () => {
    const { submit, handleError, navigate } = this.props;
    const { answer } = this.state;

    this.setState({ loading: true }, () => {
      console.log('setState', this.state)
      try {
        submit({ answer, ...this.props }).then(({ errors, status }) => {
          this.setState({ answer: '' });
          if (status && status === 200) {
            navigate();
          } else if (status === 401) {
            this.setState({ showError: true });
          } else {
            handleError(errors[0]);
          }
        });
      } catch (err) {
        console.log(err);
      }
    });

    this.setState({ loading: false });
  };

当我检查我的控制台日志时,我发现状态没有更新,加载仍然是假的。

我在这里缺少什么?

2 个答案:

答案 0 :(得分:3)

这种情况正在发生,因为您在功能结束时正在调用this.setState({ loading: false });

您正在同时设置loading: trueloading: false。当您的回调正在调用时,最后一个setState函数也将状态值更改为false。

收到请求后,您应该将加载状态设置为false:

submitSecurityAnswer = () => {
  const { submit, handleError, navigate } = this.props;
  const { answer } = this.state;

  this.setState({ loading: true }, () => {
    console.log('setState', this.state)
    try {
      submit({ answer, ...this.props }).then(({ errors, status }) => {
        this.setState({ answer: '' });
        if (status && status === 200) {
          navigate();
        } else if (status === 401) {
          this.setState({ showError: true, loading: false });
        } else {
          handleError(errors[0]);
        }
      });
    } catch (err) {
      console.log(err);
    }
  });
};

答案 1 :(得分:2)

这是因为您在异步操作完成之前将loading设置为false 只需在this.setState({ loading: false });;

中移动callback即可

修改
作为评论的后续内容:

  

我尝试删除它但看到了相同的结果

我没有说要在setstate的回调中将移动删除它。
发生的情况是,您在相同的调用堆栈迭代中将其设置为true然后false,而不是等待异步操作完成。

请考虑与您的代码类似的场景:
在此示例中,我在异步操作(loading)完成之前将setTimeout设置为false,因此我只是在不等待的情况下覆盖先前的状态。

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      loading: false,
      message: ''
    };
  }

  componentDidMount() {
    this.setState({ loading: true }, () => {
      console.log(this.state);
      setTimeout(() => {
        this.setState({
          message: 'we have data'
        });
        console.log(this.state);
      }, 500);
    });

    this.setState({ loading: false });
  }

  render() {
  const {message, loading} = this.state;
    return (
      <div>
        {loading ? <div>Loading...</div> : <div>{message}</div>}
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

修复将在回调中移动下一个状态更改:
在这个例子中,我在异步操作完成后在回调中移动了行this.setState({ loading: false });,这修复了不需要的行为。

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      loading: false,
      message: ''
    };
  }

  componentDidMount() {
    this.setState({ loading: true }, () => {
      console.log(this.state);
      setTimeout(() => {
        this.setState({
          message: 'we have data'
        });
        this.setState({ loading: false });
      }, 500);
    });

  }

  render() {
    const {message, loading} = this.state;
    return (
      <div>
       {loading ? <div>loading...</div> : <div>{message}</div>}
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>