开发者问题收集

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

2017-07-07
836

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

第一次调用 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}/>

Sassan
2017-07-07

React的基本思想是,每当您调用SetState函数时,React组件都会更新,这会导致componentDidupdate在更新组件时再次调用该函数。

现在问题是您在componentDidupdate中调用setState函数,这会导致组件再次更新,并且该链永远继续进行。并且每次将componentDidupdate称为concat concat to todo的值。因此,有时间到达内存并带来错误时的时间。您不应在诸如ComponentWillUpdate,ComponentDidupDate等函数中调用SetState函数。

一种解决方案可以是使用ComponentWillReceiveProps代替ComponentDidupDate函数:

887259590
Prakash Sharma
2017-07-07