睁眼写BUG,闭眼改BUG。

React 正确的使用 State

2020.05.28

正确的使用 State

不要直接修改 State

// Wrong
this.state.comment = 'Hello';

// Correct
this.setState({comment: 'Hello'});

构造函数是唯一可以给this.state赋值的地方

   constructor(props) {
       super(props);
       this.state = {
           date: new Date(),
       }
   }

State 的更新可能是异步的

出于性能考虑, React 可能会把多个setState()调用合并成一个调用。

因为this.propsthis.state可能会异步更新, 所以不要依赖他们的值来更新下一个状态。

例如,此代码可能会无法更新计数器:

// Wrong
this.setState({
  counter: this.state.counter + this.props.increment,
})

要解决这个问题,可以让setState()接收一个函数而不是一个对象。这个函数用上一个state作为第一个参数,将此次更新被应用时的props做为第二个参数:

// Correct
this.setState((state, props) => ({
  counter: state.counter + props.increment
}));
// Correct
this.setState(function(state, props) {
  return {
    counter: state.counter + props.increment
  }
});

State 的更新会被合并

当调用setState()的时候, React会把你提供的对象合并到当前的state。

例如:您的state包含几个独立变量:

constructor(props) {
  super(props);
  this.state = {
    posts: [],
    comments: []
  }
}

可以分别调用setState()来单独地更新它们:

componentDidMount() {
  fetchPosts().then(response => {
    this.setState({
      posts: response.posts
    });
  });

  fetchComments().then(response => {
    this.setState({
      comments: response.comments
    });
  });
}

这里的合并是浅合并,所以this.setState({comments})完整保留了this.state.posts, 但是完全替换了this.state.comments.

数据是向下流动的

不管是父组件或是子组件都无法知道某个组件是有状态的还是无状态的,并且它们也不关心它是函数组件还是class组件。

这就是为什么称state为局部的或是封装的原因。除了拥有并设置了它的组件,其他组件都无法访问。

组件可以选择把它的state作为props向下传递到它的子组件中:

<h2>It is {this.state.date.toLocaleTimeString()}.</h2>

这对于自定义组件同样适用:

<FormatteDate date={this.state.date} />

FormattedDate组件会在其props中接收参数date,但是组件本身无法知道它是来自于Clock的state,或是Clock的props,还是手动输入的:

function FormattedDate(props) {
  return <h2>It is {props.date.toLocaleTimeString()}.</h2>;
}

参考

【React】React.State&生命周期