setState方法

  • setstate资源:方法详解
  • 细节注意:事实上,setState 方法与包含在其中的执行是一个很复杂的过程,从 React 最初的版本到现在,也有无数次的修改。它的工作除了要更动 this.state 之外,还要负责触发重新渲染,这里面要经过 React 核心 diff 算法,最终才能决定是否要进行重渲染,以及如何渲染。而且为了批次与效能的理由,多个 setState 呼叫有可能在执行过程中还需要被合并,所以它被设计以延时的来进行执行是相当合理的。 在 React 的 setState 函数实现中,会根据一个变量 isBatchingUpdates 判断是直接更新 this.state 还是放到 队列中回头再说,而 isBatchingUpdates 默认是 false,也就表示 setState 会同步更新 this.state,但是,有 一个函数 batchedUpdates,这个函数会把 isBatchingUpdates 修改为 true,而当 React 在调用事件处理函 数之前就会调用这个 batchedUpdates,造成的后果,就是由 React 控制的事件处理过程 setState 不会同步
    更新 this.state。
    由 React 控制的事件处理过程 setState 不会同步更新 this.state!
    也就是说,在 React 控制之外的情况, setState 会同步更新 this.state!
  • this.setState是异步,所以在this.setState之后立即调用this.state是获取不到最新的数据的,那么怎么获取最新的数据呢?有三个方法:

    1.回调函数callback

    1. this.setState({val: this.state.val+1},
    2. () => {console.log(this.state.val)});

2.componentDidUpdate

  1. componentDidUpdate(){console.log(this.state.val);}

在this.setState之后去componentDidUpdate函数中调用,此时的this.state已经更新

3.将this.setState放入setTimeout函数中

  1. let self = this;
  2. setTimeout(function () {
  3. self.setState({val:self.state.val+1});
  4. console.log(self.state.val);})

在setTimeout函数中,在this.setState之后this.state是立即更新的,所以也可以获取到更新后的数据。

  • setState(newState [,callback])

setState是更新组件中的state内容。但是,它一般是异步的,倘若设置完就使用新的state可能得不到我们想要的结果,例如:

  1. this.state = {init:1}
  2. this.setState({init:2})
  3. console.log(this.state.init); // 输出结果为:1
  4. //----------但是,我们明明是想要结果为 2------so~~~回调函数就解决了这个问题~~~-------
  5. this.setState({init:2}, ()=>{
  6. console.log(this.state.init); // 输出结果为:2})

可以看出,set state中的回调函数作用大致和componentDidUpdate生命周期类似。

setState方法将组件的更改排入队列,并且告诉React使用更改后的状态更新组件;而React会在必要的时候一起更新几个组件,而不是每次都立即进行更新。所以,需要将setState视为请求,而不是一个立即执行函数。建议使用componentDidUpdate代替回调函数这种逻辑
setState存在隐患,由于它是异步的,并且有可能是同一周期同一批次进行处理,会出现问题:后一个更改替代了前一个更改,原本想要quantity +2,由于异步批次处理,只加1.

  1. Object.assign(previousState,{quantity: state.quantity + 1},
  2. {quantity: state.quantity + 1},...)

倘若下一个状态取决于先前的状态,不建议使用以下的形式。

  1. //wrong
  2. this.setState({counter: this.state.counter + this.props.increment,});

而是:

  1. //correct
  2. this.setState((prevState, props) => ({
  3. counter: prevState.counter + props.increment}));

组件

组件名称必须以大写字母开头。
React 会将以小写字母开头的组件视为原生 DOM 标签。例如,

代表 HTML 的 div 标签,而 则代表一个组件,并且需在作用域内使用 welcome。

setState() 的三件事:

不要直接修改State
例如,此代码不会重新渲染组件:

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

而是应该使用setState():

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

构造函数是唯一可以给 this.setstate 赋值的地方:
State的更新可能是异步的
出于性能考虑,React 可能会把多个setState()调用合并成一个调用。
因为 this.props 和 this.setstate 可能会异步更新,所以你不要依赖他们的值来更新下一个状态。
例如,此代码可能会无法更新计数器:

  1. // Wrong
  2. this.setState({
  3. counter: this.state.counter + this.props.increment,
  4. });

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

  1. // Correct
  2. this.setState((state, props) => ({
  3. counter: state.counter + props.increment
  4. }));

上面使用了箭头函数,不过使用普通的函数也同样可以:

  1. // Correct
  2. this.setState(function(state, props) {
  3. return {
  4. counter: state.counter + props.increment
  5. };
  6. });


State的更新会被合并
当你调用 setState() 的时候,React 会把你提供的对象合并到当前的 state。
例如,你的 state 包含几个独立的变量:

  1. constructor(props) {
  2. super(props);
  3. this.state = {
  4. posts: [],
  5. comments: []
  6. };
  7. }

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

  1. componentDidMount() {
  2. fetchPosts().then(response => {
  3. this.setState({
  4. posts: response.posts
  5. });
  6. });
  7. fetchComments().then(response => {
  8. this.setState({
  9. comments: response.comments
  10. });
  11. });
  12. }

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

Chosen 对 DOM 做的操作

如果你在一个 之后增加一个独立的具有它自身显示表现的 DOM 节点。然后它会在值变化的时候触发 jQuery 事件来通知我们这些变化。
以下代码是我们最终要实现的效果:

  1. function Example() {
  2. return (
  3. <Chosen onChange={value => console.log(value)}>
  4. <option>vanilla</option>
  5. <option>chocolate</option>
  6. <option>strawberry</option>
  7. </Chosen>
  8. );
  9. }

为了简化,我们将它实现为 uncontrolled component
首先,我会创建一个空的组件,它的 render() 函数我们返回一个包含 使用一个额外的

包裹起来。这是很必要的,因为 Chosen 会紧挨着我们传递给它的