2017-07-07 15 views
2

私はReactを学習しており、トレーニングのために、基本的なTodoアプリケーションを作成したいと思います。最初のステップでは、入力フィールドとボタンをレンダリングするAddTodoというコンポーネントを作成したいと思います。入力フィールドに何かを入力してボタンを押すたびに、入力フィールドの値を別のコンポーネントに渡しますTodoListをリストに追加します。Uncaught RangeError最大の呼び出しスタックサイズがReactアプリで超過

問題は、アプリケーションを起動すると、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(最初のtodoを追加した後であなたの場合に起こる小道具/州で)this.props.addToListthis.state.todoと状態を更新します。状態を更新するとcomponentDidUpdateが再び実行され、this.props.addToListの値が 'this.state.todo`に再度追加され、無限に進みます。

あなたはいくつかの汚れたハッキン​​グで修正することができますが、あなたのアプローチは全体的に悪い方法です。適切なことは、親コンポーネント(Main)のtodosを保持し、新しいTodoをsetNewTodoに追加します(恐らくaddTodoに名前を変更することがあります)、todoリストをMain州からTodoList<TodoList todos={this.state.todos}/>に渡します。

1

反応の基本的な考え方は、setState関数を呼び出すたびに反応するコンポーネントが更新され、コンポーネントが更新されたときに関数componentDidUpdateが再び呼び出されるようにします。

ここで問題は、componentDidUpdate内でsetState関数を呼び出して、コンポーネントが再び更新され、このチェーンが永遠に続くことです。また、componentDidUpdateが呼び出されるたびにtodoに値を連結します。だから、メモリがいっぱいになってエラーが発生する時が来ます。

 componentDidUpdate(nextProps) { 
      var newTodo = nextProps.addToList; 
      this.setState(prevState => ({ 
       todos: prevState.todos.concat(newTodo) 
      })); 
     } 
:あなたは一つの解決策は次のように代わりにcomponentDidUpdate機能のcomponentWillReceivePropsを使用することができ

などcomponentDidUpdate、componentWillUpdateのような関数の内部でSETSTATE関数を呼び出すべきではありません
関連する問題