React - 状态未更新或重置为旧状态

React - State not updated or getting reset to old state

我正在尝试构建一个具有输入字段功能的聊天应用程序,它可以用作 chat_groups 数组的过滤器,该数组处于 chat_groups。这是我的代码的样子:

    constructor(props) {
    super(props);
    this.state = {
      currUserId: "--id--",
      chats: [],
      chat_groups: [],
      users: [],
    };
  }
  .
  .
  .
  <input
className="chat-group__search__input"
placeholder="Search for group..."
onChange={(ev) => {
    console.log(ev.currentTarget.value);
    var thatState = this.state;
    thatState.chat_groups = thatState.chat_groups.map(
    (gp) => {
        gp["visible"] = gp.group_name
        .toLowerCase()
        .includes(ev.currentTarget.value);
        return gp;
    }
    );
    // getting correct state in thatState variable
    this.setState(thatState);
}}
/>
// getting old state in setState callback and componentDidUpdate lifecycle

奇怪的问题是我在设置状态之前在那个状态变量中得到了正确的值。但是在调用 setState 函数后,如果我尝试检查 setState 回调或 componentDidUpdate 生命周期中的状态,我只会得到旧状态。

我也为按键和更改事件尝试过。所以,似乎也不是事件的问题。

我想知道代码中是否存在明显的问题,或者我可以采取哪些措施来调试该问题。

编辑: 更改后,我当前的 onChange 如下所示,但问题仍然存在; setState 函数似乎没有改变状态,因为我只能在 componentDidUpdate 生命周期和 setState 回调中看到旧状态。

 onChange={(ev) => {
                      console.log(ev.currentTarget.value);
                      let chat_groups = this.state.chat_groups.map((gp) => ({
                        ...gp,
                        visible: gp.group_name
                          .toLowerCase()
                          .includes(ev.currentTarget.value),
                      }));
                      console.log(
                        "Before",
                        chat_groups.map((gp) => gp.visible)
                      );
                      this.setState({ chat_groups: chat_groups });
                    }}

不,不要这样做var thatState = this.state它只是一个对象,它很容易发生变异,你不会得到更新,因为反应状态变化从未发生过。

而不是这样做var { chat_groups } = this.state然后进一步使用它并最后设置状态this.setState({ chat_groups: chat_groups })也尽量避免突变意味着复制chat_groups的值也

看起来你在尝试直接操作状态,这在 React 中是一个很大的禁忌。

onChange={(ev) => {
    this.setState({
        chat_groups: this.state.chat_groups.map((gp) => {
            gp["visible"] = gp.group_name
            .toLowerCase()
            .includes(ev.currentTarget.value);
            return gp;
        })
    });
}}

问题是你正在改变 state

当您执行 var thatState = this.state; 时,两个对象的引用仍然相同。因此,当您更新 thatState.chat_groups 时,您也会自动成为 updating/mutating state

将您的 onChange 方法更改为喜欢以下内容

onChange = ev => {
  console.log(ev.currentTarget.value);
  let { chat_groups } = this.state;
  chat_groups = chat_groups.map(gp => ({
      ...gp,
      visible: gp.group_name.toLowerCase().includes(ev.currentTarget.value)
  }));

  this.setState(state => ({
    ...state,
    chat_groups
  }));
};
//Other code
//....
//....
<input
  className="chat-group__search__input"
  placeholder="Search for group..."
  onChange={this.onChange} />

我怀疑在使用输入值检查 group_name 时存在一个问题,即您正在使用 gp.group_name.toLowerCase()group_name 转换为 lower case,但输入值您未转换为 lower case。这可能是 visible 属性值未更新的原因之一。因此,在下面的代码片段中,我在比较时也将输入值转换为 lower case

在这里,下面是符合您要求的可运行代码段。在 setState 的回调函数中执行 console.log 并且状态正在更新。

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      currUserId: "--id--",
      chats: [],
      chat_groups: [{
        group_name: "Group One"
      }, {
        group_name: "Group Two"
      }],
      users: []
    }
  }

  onChange = ev => {
    console.log(ev.currentTarget.value);
    let {
      chat_groups
    } = this.state;
    chat_groups = chat_groups.map(gp => ({
      ...gp,
      visible: gp.group_name.toLowerCase().includes(ev.currentTarget.value.toLowerCase())
    }));
    this.setState(state => ({
      ...state,
      chat_groups
    }), () => { console.log(this.state.chat_groups); });
  };
  
  render() {
    return <input 
      placeholder="Search for group..."
      onChange={this.onChange} />
  }
}

ReactDOM.render(<App />, document.getElementById("react"));
.as-console-wrapper {
  max-height: 100% !important;
}
<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="react"></div>

只能使用 setState 方法更新状态。

您正在直接在上面的代码中改变状态 - this isn't recommended。你会得到意想不到的结果,这是不可预测的。

您应该这样做 - 创建一个新的更新对象并将其传递给 setState

onChange={(ev) => {
  console.log(ev.currentTarget.value);

  const updatedChatGroups = this.state.chat_groups.map((gp) => {
    const visible = gp.group_name.toLowerCase().includes(ev.currentTarget.value);

    return {
      ...gp,
      visible,
    };
  });

  // Update the modified object using this.setState().
  this.setState({ chat_groups: updatedChatGroups });
}}

Read More