我遇到了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;
答案 0 :(得分:3)
在Todo
的渲染方法中,您调用remove
,这是您的错误状态更新发生的地方。
要解决此问题,请从更新状态的handleRemove
TodoApp
方法返回一个函数。简化版:
handleRemove(id) {
return () => {
...
this.setState({ data: remainder });
}
}
此处值得注意的是,由于您使用的是当前状态,因此最好使用setState
回调(将prevState
作为参数),而不是依赖在this.state
。
答案 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>)
};