当前位置: 首页 > 知识库问答 >
问题:

警告:setState(...):无法在现有状态转换期间更新

公西永嘉
2023-03-14

我正在开发一个简单的待办事项列表反应应用程序(新的React.js)。我已经将项目添加到工作列表中,但删除项目会引起一个问题。在我的父反应组件中,我有以下代码:

import ToDoEntries from './to_do_entries.jsx';

class ToDoList extends React.Component {
  constructor(props) {
    super(props);
    this.state = { list: [] }
    this.add = this.addItem.bind(this);
    this.removeItem = this.removeItem.bind(this);
  }

  addItem(e) { //removed to avoid tl:dr }

  render() {
    return(
      <form onSubmit={this.add}>
        <input placeholder='Enter item' type='text' ref={(el) => {this._input = el;} }/>
        <button>Add</button>
      </form>

      <ToDoEntries entries={this.state.list}
        removeCallback={this.removeItem}
      />
    );
  }

}

我的待办事项。jsx组件:

class ToDoEntries extends React.Component {
  constructor(props) {
    super(props);
  }

  renderItems() {
    const { entries, removeCallback } = this.props;

    function createTasks(item) {
      return <li key={item.key}>{item.text}</li>
    }

    var listItems = entries.map(function(item) {
      return(<li onClick={removeCallback} key={item.key}>{item.text}</li>)
    })

    return listItems;
  }

  render() {
    var todoEntries = this.renderItems();

    return(
      <ul>
        {todoEntries}
      </ul>
    );
  }
}

export default ToDoEntries;

运行此代码将带来:

警告:setState(...):无法在现有状态转换期间更新

问题:

为什么to_do_entries.jsx的渲染在添加项时立即执行回调,即:

var listItems = entries.map(function(item) {
  return(<li onClick={removeCallback(id)} key={item.key}>{item.text}</li>)
})

但是,添加. bind(null, id)以删除Callback ie。

共有3个答案

翟鸿振
2023-03-14

为什么要输入。jsx的渲染是否立即执行回调?

那么,当您映射到todo的每个

所以现在的代码

<li onClick={removeCallback(id)} </li>

相当于:

var result = removeCallback(id);
<li onClick={result} </li>

您已经正确地指出,使用bind将起作用。这是由于这种行为使得它在这些情况下非常有用。

有关更多信息,请参阅mdn文档,但我将在此处引用重要部分:

bind。。。创建并返回一个新函数,该函数在调用时。。。

在您的情况下,当使用bind并将其赋予onClick时,您正在创建一个新函数,该函数将在实际触发click事件时调用,而不是在渲染元素时调用。

查看removeCallback的另一种方法。绑定(null,id)是这样的:

var newFunc = () => {
  return removeCallback(id);
}
<li onClick={newFunc} </li>

彭修筠
2023-03-14

我建议不要这样做,并使用与我为您写的示例相似的方法。呈现绑定到状态的待办事项列表,然后将相关信息传回给父组件以删除该项。在这种情况下,我使用todo的索引来拼接数组,以便将其删除。

当每个todo

但是,这通常被认为是一种不好的做法,因为每次组件运行时,它都会一次又一次地创建此函数。将此值乘以屏幕上的待办事项数量,您将失去性能。这是一个小问题,但我的示例演示了如何解决这个问题。https://codepen.io/w7sang/pen/VWNLJp

// App
class App extends React.Component{
  constructor(props) {
    super(props);
    this.state = { list: [] }
    this.add = this.addItem.bind(this);
    this.removeItem = this.removeItem.bind(this);
  }
  addItem(e) { 
    e.preventDefault();
    this.setState({
      list: [ 
        ...this.state.list, 
        {
          key: Math.random(1,10000),
          text: this._input.value
        }
      ]
    })
  }
  removeItem(payload){
    this.setState({
      list: [ 
        ...this.state.list.slice(0, payload.index),
        ...this.state.list.slice(payload.index + 1)
      ]
    })
  }
  render() {
    return(
      <div>
        <form onSubmit={this.add}>
          <input placeholder='Enter item' type='text' ref={(el) => {this._input = el;} }/>
          <button>Add</button>
        </form>
        <ToDoEntries entries={this.state.list} removeItem={this.removeItem} />
      </div>
    );
  }
}

// TodoEntries [STATELESS]
const ToDoEntries = ({ entries, removeItem } ) => {
  return(
    <ul>
      { entries.map((item, index) => {
        return(<Todo key={item.key} index={index} item={item} removeItem={removeItem} />)
      }) }
    </ul>
  );
}

// Todo
class Todo extends React.Component {
  constructor(props){
    super(props);
    this.state = {};
    this.remove = this.remove.bind(this);
  }
  remove() {
    const { index, removeItem } = this.props;
    removeItem({
      index
    });
  }
  render() {
    return <li onClick={this.remove}>{this.props.item.text}</li>
  }
}

ReactDOM.render(<App />,document.getElementById('app'));
<div id="app"></div>

顾兴昌
2023-03-14

问题在于这一部分:

onClick={removeCallback(id)}

我们需要将函数传递给onClick,而不是值。当我们将()与functionName一起使用时,这意味着您正在调用该方法并将该方法的结果分配给onClick,如果您在removeCallback中执行设置状态,则将创建一个无限循环,因为此循环

render ->  removeCallback()  ->  setState ->
  ^                                         |
  |                                         |
  |                                         |
   -----------------------------------------

这就是为什么会出现错误。

检查代码段中abc和abc()的区别:

function abc(){
   return 'Hello';
}

console.log('without () = ', abc);     //will return the function
 
console.log('with () = ', abc());      //will return the function result (value)
 类似资料:
  • 问题内容: 我正在尝试从渲染视图重构以下代码: 到绑定位于构造函数内的版本。原因是渲染视图中的绑定会给我带来性能问题,尤其是在低端手机上。 我创建了以下代码,但是我不断收到以下错误(很多错误)。该应用似乎陷入了循环: 以下是我使用的代码: 问题答案: 看起来您不小心在render方法中调用了该方法,而您可能想这样做。 如果您不想在onClick处理程序中创建lambda,我认为您将需要两个绑定方法

  • 我正在重写一些旧的ReactJS代码,但在修复此错误时遇到了麻烦(此错误在控制台中重复大约1700次,DOM根本不呈现): 警告:设置状态(…):无法在现有状态转换期间更新(例如在或其他组件的构造函数中)。渲染方法应该是道具和状态的纯函数;构造函数的副作用是一种反模式,但可以移动到。 我是一个组件,它将它的状态传递给一个应该呈现一些控件的组件。基于单击的控件,状态应该更改,并且应该呈现新的控件。

  • 在进一步的调试中,我发现,以上可能不是根本原因,毕竟,我可以保留通知,但我需要删除我的重定向。

  • 当我试图插入一个新的食谱元素时,我的项目总是崩溃。我使用在能够根据需要更新食谱(例如删除,编辑等)。 如果我将语句切换到,我可以插入元素而没有问题,但是由于删除,我无法删除触发状态更改,并需要状态更改来反映更新而不是道具。有人对这个问题有什么建议吗?谢谢! 配方列表: 配方容器: 配方表:

  • 错误消息: 反应:警告setState无法在现有状态转换期间更新(例如在渲染中) 这是一个react原生应用程序,但我认为,这更多的是一个react问题。 我得到了标题中描述的错误。但我对原因感到困惑,我没有在任何父组件或子组件中设置状态。因此,我有一个孙子组件(CardLayoutResult),它呈现一个listView,每一行呈现一个新组件(Render row),该组件有一个单击事件,单击