React App 中未捕获的 RangeError 最大调用堆栈大小超出
我正在学习 React,为了进行培训,我想创建一个基本的 Todo 应用。第一步,我想创建一个名为 AddTodo 的组件,该组件呈现一个输入字段和一个按钮,每次我在输入字段中输入内容并按下按钮时,我都想将输入字段的值传递给另一个名为 TodoList 的组件并将其附加到列表中。
问题是,当我启动应用程序时,AddTodo 组件成功呈现,但当我输入内容并按下按钮时,应用程序停止响应 2 秒,之后出现此信息:
Uncaught RangeError: Maximum call stack size reached
并且什么也没发生。
我的应用程序源代码: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;
第一次调用
componentDidUpdate
时(发生在其 props/state 首次更改之后,在您的情况下发生在添加第一个待办事项之后),它会将
this.props.addToList
添加到
this.state.todo
并更新状态。更新状态将再次运行
componentDidUpdate
,它会再次将
this.props.addToList
的值添加到 'this.state.todo`,并无限期地运行。
您可以使用一些肮脏的黑客来修复它,但您的方法总体上是一种糟糕的方法。正确的做法是将待办事项保留在父组件(
Main
)中,在
setNewTodo
中将新的待办事项附加到其中(您可能将其重命名为
addTodo
)并将待办事项列表从
Main
状态传递到
TodoList
:例如
<TodoList todos={this.state.todos}/>
。
React的基本思想是,每当您调用SetState函数时,React组件都会更新,这会导致componentDidupdate在更新组件时再次调用该函数。
现在问题是您在componentDidupdate中调用setState函数,这会导致组件再次更新,并且该链永远继续进行。并且每次将componentDidupdate称为concat concat to todo的值。因此,有时间到达内存并带来错误时的时间。您不应在诸如ComponentWillUpdate,ComponentDidupDate等函数中调用SetState函数。
一种解决方案可以是使用ComponentWillReceiveProps代替ComponentDidupDate函数:
887259590