setState意外更新非状态属性

Phi*_*ong 5 javascript reactjs

我不知道这是一个已知的问题还是一个预期的功能,但我发现了一个有趣的问题.

所以我们都知道如果我们想在React中呈现一个反应值,我们必须将值放在状态并使用setState:

constructor() {
  super();
  this.state = { counter: 0 }
  this.incrementButtonListener = (e) => {
    e.preventDefault();
    this.setState(prevState => ({ counter: prevState.counter + 1 }));
  };
}

render() {
  return (
    <div>
      <h1>{this.state.counter}</h1>
      // When clicked, counter increments by 1 and re-renders
      <button onChange={this.incrementButtonListener}>Increment</button> 
    </div>
  )
}
Run Code Online (Sandbox Code Playgroud)

但是如果我们counter作为一个字段属性,render()将只捕获counter创建组件的快照,即使counter递增,结果也不会在render()中被反应显示:

constructor() {
  super();
  this.counter = 0;
  this.incrementButtonListener = (e) => {
    e.preventDefault();
    this.counter++;
  };
}

render() {
  return (
    <div>
      <h1>{this.counter}</h1>
      // When clicked, counter increments by 1 but the difference is NOT rendered
      <button onChange={this.incrementButtonListener}>Increment</button> 
    </div>
  )
}
Run Code Online (Sandbox Code Playgroud)

对?基本的东西.

然而,当我试图摆弄这段代码时,有一个有趣的发生.我们将反击作为一个场地财产,其他一切都完好无损.唯一的区别是,在incrementButtonListener,我要添加setStatesomeStateProperty:

constructor() {
  super();
  this.counter = 0;
  this.incrementButtonListener = (e) => {
    e.preventDefault();
    this.counter++;
    /*-------------------------------ADD THIS*/
    this.setState({});
    // You have to pass an object, even if it's empty. this.setState() won't work.
    /*-----------------------------------------*/
  };
}

render() {
  return (
    <div>
      <h1>{this.counter}</h1>
      // Surprise surprise, now this.counter will update as if it was in the state! 
      <button onChange={this.incrementButtonListener}>Increment</button> 
    </div>
  )
}
Run Code Online (Sandbox Code Playgroud)

这一次,this.counter更新,好像它处于状态!

所以我的假设是,每次调用setState时(即使使用空对象作为参数),render()this.counter也会再次运行并重新计算,从而递增.当然,它不会像国家财产那样100%被动.但是,在这个用例中,唯一的时间this.counter会改变,就是当我点击Increment按钮时.所以,如果我在监听器中放置一个setState,它就好像this.counter处于状态一样.

现在,我不确定这是一个可接受的行为还是一个意外的黑客行为,以及我是否应该使用它.有人能帮我解释一下吗?

如果你想看到行动中的行为,这是一个小提琴.您可以注释this.setState({})第7行中的位以查看差异.

Ste*_*han 1

因为您没有拦截状态的更改,所以它会导致重新渲染,从而导致使用增量实例属性。这是设计使然。React 状态的任何更改都会导致组件重新渲染,除非您使用生命周期钩子来控制是否应该发生这种情况。

请参阅https://reactjs.org/docs/react-component.html#shouldcomponentupdate