我正在学习React和培训,我想创建一个基本的Todo应用程序 . 对于第一步,我想创建一个名为AddTodo的组件,它呈现一个输入字段和一个按钮,每次我在输入字段中输入内容并按下按钮,我想将输入字段的值传递给另一个名为TodoList并将其附加到列表中 .
问题是,当我启动应用程序时,AddTodo组件成功呈现,但当我输入内容并按下按钮时,应用程序停止响应2秒钟,之后,我得到: Uncaught RangeError: Maximum call stack size exceeded
并且没有任何反应 .
我的应用程序源代码:Main.jsx
import React, {Component} from 'react';
import TodoList from 'TodoList';
import AddTodo from 'AddTodo';
class Main extends Component {
constructor(props) {
super(props);
this.setNewTodo = this.setNewTodo.bind(this);
this.state = {
newTodo: ''
};
}
setNewTodo(todo) {
this.setState({
newTodo: todo
});
}
render() {
var {newTodo} = this.state;
return (
<div>
<TodoList addToList={newTodo} />
<AddTodo setTodo={this.setNewTodo}/>
</div>
);
}
}
export default Main;
AddTodo.jsx
import React, {Component} from 'react';
class AddTodo extends Component {
constructor(props) {
super(props);
this.handleNewTodo = this.handleNewTodo.bind(this);
}
handleNewTodo() {
var todo = this.refs.todo.value;
this.refs.todo.value = '';
if (todo) {
this.props.setTodo(todo);
}
}
render() {
return (
<div>
<input type="text" ref="todo" />
<button onClick={this.handleNewTodo}>Add to Todo List</button>
</div>
);
}
}
AddTodo.propTypes = {
setTodo: React.PropTypes.func.isRequired
};
export default AddTodo;
TodoList.jsx
import React, {Component} from 'react';
class TodoList extends Component {
constructor(props) {
super(props);
this.renderItems = this.renderItems.bind(this);
this.state = {
todos: []
};
}
componentDidUpdate() {
var newTodo = this.props.addToList;
var todos = this.state.todos;
todos = todos.concat(newTodo);
this.setState({
todos: todos
});
}
renderItems() {
var todos = this.state.todos;
todos.map((item) => {
<h4>{item}</h4>
});
}
render() {
return (
<div>
{this.renderItems()}
</div>
);
}
}
export default TodoList;
2 回答
反应的基本思想是每当你调用setState函数时,react组件都会更新,这会导致在更新组件时再次调用函数componentDidUpdate .
现在的问题是你在componentDidUpdate中调用setState函数,这会导致组件再次更新,这个链将永远存在 . 每次调用componentDidUpdate时,它都会将一个值连接到todo . 因此,当内存变满并且抛出错误的时候到了 . 你不应该在componentWillUpdate,componentDidUpdate等函数中调用setState函数 .
一种解决方案可以是使用componentWillReceiveProps而不是componentDidUpdate函数,如下所示:
第一次调用
componentDidUpdate
(在第一次更改其道具/状态后发生,在你的情况下在添加第一个待办事项后发生)它将this.props.addToList
添加到this.state.todo
并更新状态 . 更新状态将再次运行componentDidUpdate
并再次将this.props.addToList
的值添加到'this.state.todo`并且无限循环 .你可以用一些肮脏的黑客修复它,但你的方法总体来说是一个糟糕的方法 . 正确的做法是将待办事项保存在父组件(
Main
)中,在setNewTodo
中附加新的待办事项(您可能将其重命名为addTodo
)并将待办事项列表从Main
状态传递给TodoList
:<TodoList todos={this.state.todos}/>
.