简体   繁体   English

React setState 不适用于 if 语句

[英]React setState doesn't work with if statement

I don't understand why below code doesn't change state.我不明白为什么下面的代码不会改变状态。 Even when 'if' statement is executed, state is the same.即使执行“if”语句,状态也是一样的。 Why case with if doesn't change state?为什么if情况不会改变状态?

 class Welcome extends React.Component { state = { items: [ { id: 1, done: false, }, { id: 2, done: false, }, { id: 3, done: false, }, ] } handleDone = (index) => { this.setState((prevState) => { const copyItems = [...prevState.items]; if (copyItems[index].done === false) { console.log("Done should be true"); copyItems[index].done = true; } else { console.log("Done should be false"); copyItems[index].done = false; } // copyItems[index].done = !copyItems[index].done - the same result return { items: [...copyItems], }; }); } render() { return ( this.state.items.map((item, index) => { return ( <div> <span>id: {item.id}</span> <span> {item.done ? "- is not done" : "- is done"} </span> <button onClick={() => this.handleDone(index)}> Change to opposite </button> </div> ) }) ) } } ReactDOM.render(<Welcome />, document.body);
 <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>

this.setState((prevState) => {
  const copyItems = [...prevState.items];

  if (copyItems[index].done === false) {
    console.log("Done should be true");
    copyItems[index].done = true;
  } else {
    console.log("Done should be false");
    copyItems[index].done = false;
  }

  // copyItems[index].done = !copyItems[index].done - the same result

  return {
    items: [...copyItems],
  };
});

Below example works fine when there is no if statement:当没有if语句时,下面的示例工作正常:

this.setState((prevState) => {
  const copyItems = [...prevState.items];

  copyItems[index].done = true;
 
  return {
    items: [...copyItems],
  };
});

Below example works fine with 'if' statement in case when object is copied:下面的示例适用于“if”语句,以防复制对象:

this.setState((prevState) => {
  const copyItems = JSON.parse(JSON.stringify([...prevState.items]));

  copyItems[index].done = !copyItems[index].done

  return {
    items: [...copyItems],
  };
});

What's wrong for React is that even if you spread your array, the object inside it are still referenced as the object inside your state. React 的错误在于,即使您展开数组,其中的对象仍然被引用为您状态中的对象。 So by doing copyItems[index].done = true;所以通过执行copyItems[index].done = true; you're actually mutating the state directly (this.state[index].done should be true also).你实际上是直接改变状态(this.state[index].done 也应该是真的)。 What you can do to avoid this is to use .map on your prevState so you're not updating the state directly.为了避免这种情况,您可以做的是在 prevState 上使用 .map ,这样您就不会直接更新状态。

 const state = [{ done: true }]; const stateCopy = [...state]; const toFind = 0; stateCopy[toFind].done = false; console.log(stateCopy[toFind], state[toFind]); // { done: false } , { done: false } /!\\ state should not be updated at this point. // good way of doing that might be by using prevState.items.map() and do your logic inside it const stateUpdated = state.map((el, index) => { if (index === toFind) { return { done: !el.done } } return el; }); console.log(stateUpdated[toFind], state[toFind]) // state is not mutated, as expected

Problem was caused by create-react-app that wrap app with <React.StrictMode> .问题是由使用<React.StrictMode>包装应用程序的 create-react-app 引起的。

To resolve it just remove this wrapping tag.要解决它,只需删除此包装标签。 And that's it.就是这样。 It's expected behaviour and it should help avoid bugs on prod.这是预期的行为,它应该有助于避免产品上的错误。 More details in React docs . React 文档中的更多详细信息。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM