反应-状态未更新或重置为旧状态

时间:2020-09-28 05:50:10

标签: javascript reactjs onkeyup

我正在尝试使用输入字段的功能构建一个聊天应用程序,该功能可用作状态为 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

怪异的问题是在设置状态之前,我在thatState变量中获得了正确的值。但是在调用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 });
                    }}

4 个答案:

答案 0 :(得分:1)

问题是您正在突变state

当您执行var thatState = this.state;时,两个对象的引用仍然相同。因此,当您更新thatState.chat_groups时,您也会自动更新/更改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时存在一个问题,即您正在使用group_namelower case转换为gp.group_name.toLowerCase(),但输入值不是转换为lower case。这可能是为什么visible属性值未得到更新的一个问题。因此,在下面的代码段中,我在进行比较时也将输入值也转换为lower case

在这里,下面是您需要的可运行摘要。在console.log的回调函数中执行setState,状态正在更新。

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>

答案 1 :(得分:0)

不,不要执行此操作for (File value : hidden) { System.out.println(value); } ,它只是一个对象,很容易发生变异,您将无法获得更新,因为从未发生过反应状态更改。

执行此操作var thatState = this.state,然后进一步使用它并最后设置状态var { chat_groups } = this.state,还尝试尽可能避免突变,这也意味着也复制this.setState({ chat_groups: chat_groups })的值

答案 2 :(得分:0)

似乎您正在尝试直接操纵状态,这在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;
        })
    });
}}

答案 3 :(得分:0)

状态只能使用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