警告:setState(...):在现有状态转换期间无法更新 [英] Warning: setState(…): Cannot update during an existing state transition

查看:66
本文介绍了警告:setState(...):在现有状态转换期间无法更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm developing a simple 'to do list' react app (new to React.js). I have adding items to a list working but deleting items raises a question. Within my parent react component, i have the following code:

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}
      />
    );
  }

}

我的 to_do_entries.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(...):在现有状态期间无法更新
过渡

Warning: setState(…): Cannot update during an existing state transition

问题:

为什么 to_do_entries.jsx 的渲染会在项目获得时立即执行回调添加ie:

why does to_do_entries.jsx's render immediately execute the callback when an item gets added i.e:

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

但是,将 .bind(null,id)添加到removeCallback即。 < li onClick = {removeCallback.bind(null,id)} /> 不?

However, adding .bind(null, id) to removeCallback ie. <li onClick={removeCallback.bind(null, id)} /> does not?

推荐答案

我会反对这一点,并对我为您编写的示例使用类似的方法。渲染绑定到状态的待办事项列表,然后将相关信息传递回父组件以删除该项目。在这种情况下,我使用todo的索引来拼接数组,以便将其删除。

I would advise against that, and use a similar approach to the example I have written for you. Render a list of todo's that is bind-ed to state and then pass in the relevant information back up to your parent component to remove the item. In this case, I use the index of the todo to splice the array so that it removes it.

当呈现每个todo < li> 时,会立即调用当前的onClick,因为它只是一个函数调用造成了这个问题。 .bind 解决了这个问题,因为当你点击元素时它会创建一个新函数,这就是函数没有立即调用的原因。

Your current onClick is invoked immediately when each todo <li> is rendered because it's simply a function call which is causing the problem. .bind solves this problem because it will create a new function when you click on the element which is why the function doesn't invoke immediately.

但是,这通常被认为是不好的做法,因为每次组件都会一次又一次地创建这个功能。通过屏幕上的todo数量将其倍增,您将失去性能。这是一个小问题,但我的例子展示了如何解决这个问题。
https://codepen.io/w7sang/pen/VWNLJp

However, this is generally considered bad practice because every time the component it'll create this function again and again and again. Multiple this by the amount of todo's on the screen and you'll be losing performance. It's a small issue, but my example shows how to solve this problem. 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>

这篇关于警告:setState(...):在现有状态转换期间无法更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆