首页 文章

未捕获的RangeError React App中超出了最大调用堆栈大小

提问于
浏览
2

我正在学习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 回答

  • 1

    反应的基本思想是每当你调用setState函数时,react组件都会更新,这会导致在更新组件时再次调用函数componentDidUpdate .

    现在的问题是你在componentDidUpdate中调用setState函数,这会导致组件再次更新,这个链将永远存在 . 每次调用componentDidUpdate时,它都会将一个值连接到todo . 因此,当内存变满并且抛出错误的时候到了 . 你不应该在componentWillUpdate,componentDidUpdate等函数中调用setState函数 .

    一种解决方案可以是使用componentWillReceiveProps而不是componentDidUpdate函数,如下所示:

    componentDidUpdate(nextProps) {
                var newTodo = nextProps.addToList;
                this.setState(prevState => ({
                   todos: prevState.todos.concat(newTodo)
                }));
          }
    
  • 1

    第一次调用 componentDidUpdate (在第一次更改其道具/状态后发生,在你的情况下在添加第一个待办事项后发生)它将 this.props.addToList 添加到 this.state.todo 并更新状态 . 更新状态将再次运行 componentDidUpdate 并再次将 this.props.addToList 的值添加到'this.state.todo`并且无限循环 .

    你可以用一些肮脏的黑客修复它,但你的方法总体来说是一个糟糕的方法 . 正确的做法是将待办事项保存在父组件( Main )中,在 setNewTodo 中附加新的待办事项(您可能将其重命名为 addTodo )并将待办事项列表从 Main 状态传递给 TodoList<TodoList todos={this.state.todos}/> .

相关问题