React:在现有状态转换期间无法更新

时间:2017-05-31 19:06:44

标签: javascript reactjs

我遇到了React的问题。 当我按下" +"按钮,此控制台消息出现,没有任何反应:

Cannot update during an existing state transition (such as within `render` or another component's constructor). Render methods should be a pure function of props and state; constructor side-effects are an anti-pattern, but can be moved to `componentWillMount`

我发现了几个具有类似标题的问题,但其中常见的是在render方法中调用了带有setState的函数。

我的渲染方法没有调用,但出现错误。

为什么?

感谢您的阅读。

代码:

import React from 'react';

const TodoForm = ({addTodo}) => {
    let input;

    return (
        <div>
            <input
                ref={node => {
                    input = node;
                }}

            />
            <button onClick={() => {
                addTodo(input.value);
                input.value = '';
            }}>
                +
            </button>
        </div>
    );
};


const Todo = ({todo, remove}) => {
    // Each Todo
    return (<li onClick={remove(todo.id)}>{todo.text}</li>)
};

const TodoList = ({todos, remove}) => {
    // Map through the todos
    const todoNode = todos.map((todo) => {
        return (<Todo todo={todo} key={todo.id} remove={remove}/>)
    });
    return (<ul>{todoNode}</ul>);
};

const Title = () => {
    return (
        <div>
            <div>
                <h1>to-do</h1>
            </div>
        </div>
    );
};

window.id = 0;
class TodoApp extends React.Component {
    constructor(props) {
        // Pass props to parent class
        super(props);
        // Set initial state
        this.state = {
            data: []
        }
    }

    // Add todo handler
    addTodo(val) {
        // Assemble data
        const todo = {text: val, id: window.id++}
        // Update data
        this.state.data.push(todo);
        // Update state
        console.log('setting state...');
        this.setState({data: this.state.data});
    }

    // Handle remove
    handleRemove(id) {
        // Filter all todos except the one to be removed
        const remainder = this.state.data.filter((todo) => {
            if (todo.id !== id) return todo;
        });
        // Update state with filter
        this.setState({data: remainder});
    }

    render() {
        // Render JSX
        return (
            <div>
                <Title />
                <TodoForm addTodo={
                    (val)=>{

                        this.addTodo(val)
                    }
                }/>
                <TodoList
                    todos={this.state.data}
                    remove={this.handleRemove.bind(this)}
                />
            </div>
        );
    }
}
export default TodoApp;

2 个答案:

答案 0 :(得分:3)

Todo的渲染方法中,您调用remove,这是您的错误状态更新发生的地方。

要解决此问题,请从更新状态的handleRemove TodoApp方法返回一个函数。简化版:

handleRemove(id) {
  return () => {
    ...
    this.setState({ data: remainder });
  }
}

此处值得注意的是,由于您使用的是当前状态,因此最好使用setState回调(将prevState作为参数),而不是依赖在this.state

setState docs

答案 1 :(得分:0)

Andy_D非常有帮助,我的回答有两个解决方案:

首先进行渲染功能更改

<TodoList
    todos={this.state.data}
    remove={this.handleRemove.bind(this)}
/>

<TodoList
    todos={this.state.data}
    remove={() => this.handleRemove.bind(this)}
/>

或更改代码

const Todo = ({todo, remove}) => {
    // Each Todo
    return (<li onClick={remove(todo.id)}>{todo.text}</li>)
};

到那个:

const Todo = ({todo, remove}) => {
    // Each Todo
    return (<li onClick={() => remove(todo.id)}>{todo.text}</li>)
};