提问者:小点点

为什么React在直接变异状态时会更新?


在下面的示例中,我使用ES6映射作为React中的状态值:

null

class App extends React.Component {
  constructor(props) {
    super(props);
    const results = new Map();
    results["group1"] = [{ value: "..." }, { value: "..." }];
    this.state = { results };
  }

  onUpdateClick(i) {
    this.state.results["group1"][i].value = i;
    this.setState({});
  }

  onResetClick(i) {
    this.state.results["group1"][i].value = "...";
    this.setState({});
  }

  render() {
    const { results } = this.state;
    return (
      <div>
        {results["group1"].map((r, i) => (
          <div>
            {r.value}&nbsp;
            <button onClick={e => this.onUpdateClick(i)}>update</button>
            <button onClick={e => this.onResetClick(i)}>reset</button>
          </div>
        ))}
      </div>
    );
  }
}

ReactDOM.render(<App />, document.getElementById("container"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

<div id='container'></div>

null

当您单击按钮时,我将直接更新映射,然后调用不带参数的setState。 我不复制这张地图。 根据我对React文档的理解,这不应该起作用,并在文档中明确警告:

千万不要直接修改this.state,因为之后调用setState()可能会替换您所做的修改。 把它当作是不可变的

(https://reactjs.org/docs/react-component.html#状态)

文档还指出比较是浅层的,因此使用空对象调用肯定不会导致合并,因此不会重新呈现?

这个例子为什么管用?

(我还应该注意到,我也在React V16.9.0中重现了这种行为)

编辑:我还想指出(因为许多答案都提到我传递的是一个空对象),如果我像这样调用setState,组件将被重新呈现(和更新):

this.setState({ results: this.state.results })

这似乎不应该引起重新渲染


共3个答案

匿名用户

来自文档:setState

除非shouldComponentUpdate()返回false,否则setState()将始终导致重新呈现。

这意味着无论是否将更改作为参数传递,this.setState({});都将导致重新呈现

匿名用户

你错了:

this.setState({}); // this will do nothing.

您希望使用空对象更新状态。 但事实并非如此。

当您使用setState方法时,它期望属性更新。 但是由于您没有为setState提供任何属性,因此它将不执行任何操作。 但它仍将按setState性质重新呈现组件。

更新:到您的查询

编辑:我还想指出(因为许多答案都提到我传递的是一个空对象),如果我像这样调用setState,组件将被重新呈现(和更新):

this.setState({ results: this.state.results })

这似乎不应该引起重新渲染

React在内部声明,当您尝试用完全相同的状态更新状态时,它与this.state.results类似。 所以,没有什么可以重新渲染的。 但是当您将setState与空对象一起使用时,React将闪烁它的状态,从而重新呈现。

从文档中阅读以下注释:

避免复制道具进入状态! 这是一个常见的错误:

constructor(props) {
 super(props);
 // Don't do this!
 this.state = { color: props.color };
}

问题是它既没有必要(您可以直接使用this.props.color),又会创建bug(颜色道具的更新不会反映在状态中)。

匿名用户

当调用this.setstate时,基本上React会将传递给这个函数的参数与旧的this.state合并,以产生一个新的状态值。 例如:

this.state = Object.assign({}, this.state, passedParam);

因此,在上面的片段中,每次调用this.setState({});时,都会创建一个新的状态对象,使组件重新呈现。