2017-07-07 110 views
2

我正在學習React和培訓,我想創建一個基本的Todo應用程序。對於第一步,我想創建一個名爲AddTodo的組件,該組件會呈現一個輸入字段和一個按鈕,並且每次我在輸入字段中輸入內容並按下按鈕時,我想將輸入字段的值傳遞給另一個稱爲「 TodoList並將其追加到列表中。Uncaught RangeError在React App中超出最大調用堆棧大小

問題是,當我啓動應用程序時,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; 

回答

1

第一次componentDidUpdate被稱爲(其第一變化後發生的情況在它的道具/狀態中,在你的情況下,在添加第一個待辦事項後發生),它增加了this.props.addToListthis.state.todo並更新狀態。更新狀態將再次運行componentDidUpdate並且它將值this.props.addToList再次添加到'this.state.todo`,並且它會無限次地運行。

你可以用一些骯髒的黑客修復它,但你的方法是一個糟糕的方法。正確的做法是在父組件中保留待辦事項(Main),將新待辦事項添加到setNewTodo(您可能將其重命名爲addTodo),並將待辦事項列表從Main狀態傳遞給TodoList<TodoList todos={this.state.todos}/>例如。

1

反應的基本思想是每當你調用setState函數時,反應組件得到更新,這導致組件更新時再次調用函數componentDidUpdate。

現在問題在於你在componentDidUpdate中調用setState函數,這會導致組件再次更新,並且這個鏈永遠持續下去。並且每次componentDidUpdate被調用時,它都會將一個值連接到待辦事項。所以,當內存滿了,它會拋出一個錯誤。你不應該叫裏面像componentWillUpdate,componentDidUpdate等功能的setState功能

一種解決方案可以爲使用componentWillReceiveProps代替componentDidUpdate功能是這樣的:

 componentDidUpdate(nextProps) { 
      var newTodo = nextProps.addToList; 
      this.setState(prevState => ({ 
       todos: prevState.todos.concat(newTodo) 
      })); 
     } 
相關問題