明白react之setState

组件状况(state)是一种持有,处置惩罚和运用信息的体式格局。state包括的信息仅作用于一个给定组件的内部,并许可你依据它完成组件的一些逻辑。state通常是一个POJO(Plain Old Java[Script] Object)对象,转变它是使得组件从新render本身的体式格局之一。

state是react背地道理的主要基本观点之一,然则它也有一些特性使得它用起来会有点难以捉摸而且有可能会致使在你的运用中涌现一些预感以外的行动。

更新State
唯一你能直接写this.state的处所应当是组件的组织函数中。在其它一切处所你都应当运用this.setState函数,它接收一个对象作为参数,这个对象终究会被合并到组件的当前状况中。

而在技术上你是能够经由历程this.state={//a new object}这类体式格局直接修正状况的,然则它不会引起组件运用新的值去从新衬着,然后致使状况不一致的题目。

setState是异步的
事实上setState会引起的一致性处置惩罚(reconciliation)——从新衬着组件树的历程,是下一个属性的基本即setState是异步的。这许可我们在单个作用域内屡次挪用setState而不会触发不必要的从新衬着全部树。

这就是为何在你更新state后并不能立马看见新的值。

// 假定 this.state = { value: 0 }
this.setState({
  value: 1
});
console.log(this.state.value); // 0

React 也会尝试将屡次setState挪用组合或许批处置惩罚为一次挪用:

// 假定 this.state = { value: 0 };
this.setState({ value: this.state.value + 1});
this.setState({ value: this.state.value + 1});
this.setState({ value: this.state.value + 1});

在上面一切的挪用完成后,this.state.value将是1,而不是我们的希冀值3。那末怎样取得希冀值3呢?

setState接收一个函数作为它的参数
假如你通报一个函数作为setState的第一个参数,React将会运用在当前挪用时刻的state去挪用它并希冀你返回一个对象合并到state中。所以你能够把我们上面的代码改成下面如许即可:

// 假定 this.state = { value: 0 };
this.setState((state) => ({ value: state.value + 1}));
this.setState((state) => ({ value: state.value + 1}));
this.setState((state) => ({ value: state.value + 1}));

如许this.state.value 的值就是 3了,就和上面我们以为希冀值应当是3相一致了。
记着当在更新state为一个值的时刻应一直运用这类语法,它的盘算是基于前面的一个状况的。

setState是同步的吗???
记着你适才进修到setState是异步的。事实证明并不是一直云云。这取决于实行上下文,请看下面的例子:

render() {
  return <button onClick={this.inc}>Click to update</button>
}
  
inc() {
  console.log('before: ' + this.state.test);
  this.setState({
    test: this.state.test+1
  });
  console.log('after: ' + this.state.test);
}

点击按钮元素将会致使你的console中显现:

// click!
before: 1
after: 1
// click!
before: 2
after: 2

但假如我们增加以下代码:

componentDidMount() {
  setInterval(this.inc, 1000);
}

我们将在console中看到:

before: 1
after: 2
before: 2
after: 3

因而,我们须要进修什么时刻希冀取得哪一种行动吗?并不是云云。假定setState的确是异步是异常平安的,因为在将来它就是云云

setState接收一个回调函数
假如你须要实行一些函数,或许考证状况是不是真的有更新准确。你还能够给setState通报一个函数作为第二个参数,这个函数会在状况更新终了后取得实行。请记着因为单个块内的一切更新会被合并成一个,这将致使每一个setState中的回调中取得的state值是全更新的state。

别的一种能够保证你的代码实行是在更新完成今后的体式格局是将实行代码放在componentWillUpdate 或许 componentDidUpdate中。但是对照回调函数的体式格局,这两个要领会在shouldComponentUpdate中阻挠你的组件更新时不会被挪用。

罕见毛病
个中最罕见的毛病之一就是在组织函数中运用props设置state的值。斟酌以下代码:

class Component extends React.Component {
  constructor(props) {
    super(props);
    this.state = { value: this.props.value };
  }
  
  render() {
    return <div>The value is: {this.state.value}</div>
  }
}

假如它的父组件如许render它:

<Component value={42} />

它将会准确衬着value为42,但假如父组件中修正成以下:

<Component value={13} />

那它仍会以为this.state.value是42,这是因为React并不会烧毁组件并从新创建它——它会重用一旦衬着好的组件,而且不会从新实行组织函数。要防止这个题目,你应当不要将props赋值给state,而应在render要领中运用this.props.value。
假如你照样想要运用state(假如你的props是以一种异常庞杂的盘算的运用形式,你不愿望每一次render都实行这些庞杂的盘算),你还能够完成一种在须要的时刻才去更新state的解决方案,比方:

class Component extends React.Component {
  constructor(props) {
    super(props);
    this.state = { value: this.props.value };
  }
  componentWillReceiveProps(nextProps) {
    if(nextProps.value !== this.props.value) {
      this.setState({value: nextProps.value});
    }
  }
  render() {
    return <div>The value is: {this.state.value}</div>
  }
}

请记着任何componentWill*函数都不是一个适宜的处所去触发side effect(如ajax要求),所以请运用
componentDidUpdate(previousProps, previousState),一样也供应和上面相似的if防护语句确保在没有变化时不会实行相干代码。

写在末了的话:这篇文章在Medium中取得凌驾2.1K的赞,挺不错的,值得翻译!
翻译若有不正,迎接留言指出!

    原文作者:ylzsmallsun
    原文地址: https://segmentfault.com/a/1190000015606509
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞