2016-09-13 28 views
2

私はReact/Reduxを学習していて、私は立ち往生しています。サンプルのToDoアプリケーションで、新しいToDoが追加されたときにaddTodoアクションが実行され、store.dispatchロジックを実行できます。何が失敗するかは、hasStatePropsChanged値がfalseとして計算され、したがって子更新がないことです。React/Reduxは状態更新時に子レンダリングを起動しません

コードスニペットは、次のとおりです。

import React from 'react'; 
import { connect } from 'react-redux'; 
import { store, addTodo, completeTodo, deleteTodo, clearTodo } from './TodoState.jsx'; 

class AddTodoForm extends React.Component { 
    ... 
} 

class TodoItem extends React.Component { 
    .... 
} 

let TodoList = ({items}) => (
    <ul> 
     {items.map((item,index) => 
      <TodoItem key={index} index={index} message={item.message} completed={item.completed}/> 
     )} 
    </ul> 
) 

let TodoComponent = ({ items, onAddTodo, onCompleteTodo, onDeleteTodo, onClearTodo }) => /* expand's props */ 
    (
     <div> 
      <h1>Todo</h1> 
      <AddTodoForm onAddTodo={onAddTodo} message/> 
      <TodoList items={items} onCompleteTodo={onCompleteTodo} onDeleteTodo={onDeleteTodo} onClearTodo={onClearTodo}/> 
     </div> 
    ) 

const mapStateToProps = (state) => { 
    return { 
     items: state.todo.items 
    } 
} 

const mapDispatchToProps = (dispatch) => { 
    return { 
     onAddTodo(message) { 
      dispatch(addTodo(message)) 
     }, 
     onCompleteTodo(index) { 
      dispatch(completeTodo(index)) 
     }, 
     onDeleteTodo(index) { 
      dispatch(deleteTodo(index)) 
     }, 
     onClearTodo(index) { 
      dispatch(clearTodo(index)) 
     } 
    } 
} 

export default connect(mapStateToProps,mapDispatchToProps)(TodoComponent); 

をAddTodoFormが正しくaddTodoのアクションをディスパッチする、問題はtodolistのコンポーネントは、項目の配列は新しい配列であってもを通じて再びレンダリングされませんです。

更新日: 私のレデューサーは新しい状態を返します。ここで

減速とアクションコードです:

import { createStore } from 'redux'; 
var defaultState = { todo: { items: [] } } 

const ADD_TODO = 1; 
const COMPLETE_TODO = 2; 
const DELETE_TODO = 3; 
const CLEAR_TODO = 4; 

const addTodo = (message) => { return {type: ADD_TODO, message: message, completed: false} }; 
const completeTodo = (index) => { return {type: COMPLETE_TODO, index:index} }; 
const deleteTodo = (index) => { return {type: DELETE_TODO, index:index} }; 
const clearTodo = (index) => { return {type: CLEAR_TODO, index:index} }; 

function todoReducer(state,action) { 
    switch(action.type) { 
     case ADD_TODO: 
      var newState = Object.assign({},state); 
      newState.todo.items.push({message:action.message,completed:false}); 
      return newState; 
     case COMPLETE_TODO: 
      var newState = Object.assign({},state); 
      newState.todo.items[action.index].completed = true; 
      return newState; 
     case DELETE_TODO: 
      var items = [].concat(state.todo.items); 
      items.splice(action.index,1); 
      return Object.assign({},state,{ 
       todo: { 
        items:items 
       } 
      }); 
     case CLEAR_TODO: 
      return Object.assign({},state,{ 
       todo: { 
        items: [] 
       } 
      }); 
     default: 
      return state; 
    } 
} 

var store = createStore(todoReducer,defaultState); 

export { store, addTodo, completeTodo, deleteTodo, clearTodo }; 

おかげで、

アーロン

+0

だけでなく、同様にあなたの行動のクリエイターを追加することができ、あなたの減速コード – Tyrsius

+0

を追加してください。 – azium

+0

デバッグしましょう。console.logをレデューサーとコンポーネントに入れて結果を投稿できますか?多分何かが命名法などに間違っているかもしれません(あなたがredux devtoolsをインストールした場合、これをチェックする方が簡単です) –

答えて

2

あなたが減速状態として新しいオブジェクトを返すことを確認します。 例: return Object.assign ({}, state, {items: [...oldItems, newItem]})

ここをクリックしてください[...oldItems, newItem]これは新しい配列を作成します。あなたの場合、Object.assignは浅いコピーのみを行い、実際にはアイテムは変更されていますが、同じ参照を保持しています。作業例を見て:

import React from 'react';                        
import { render } from 'react-dom';                      
import { connect, Provider } from 'react-redux';                   

import { createStore } from 'redux';                      

var defaultState = { todo: { items: [] } }                    

const ADD_TODO = 1;                          
const COMPLETE_TODO = 2;                         
const DELETE_TODO = 3;                         
const CLEAR_TODO = 4;                          

const addTodo = (message) => { return {type: ADD_TODO, message: message, completed: false} };        
const completeTodo = (index) => { return {type: COMPLETE_TODO, index:index} };           
const deleteTodo = (index) => { return {type: DELETE_TODO, index:index} };            
const clearTodo = (index) => { return {type: CLEAR_TODO, index:index} };             

function todoReducer(state,action) {                      
    switch(action.type) {                         
     case ADD_TODO:                         
      var newItem = {message:action.message,completed:false};              
      return Object.assign({},state, {todo: {items: [...state.todo.items, newItem]}});        
     case COMPLETE_TODO:                        
      var newState = Object.assign({},state);                  
      newState.todo.items[action.index].completed = true;               
      return newState;                        
     case DELETE_TODO:                         
      var items = [].concat(state.todo.items);                  
      items.splice(action.index,1);                     
      return Object.assign({},state,{                    
       todo: {                         
        items:items                       
       }                           
      });                           
     case CLEAR_TODO:                         
      return Object.assign({},state,{                    
       todo: {                         
        items: []                        
       }                           
      });                           
     default:                           
      return state;                         
    }                              
}                               

var store = createStore(todoReducer,defaultState);                  

class AddTodoForm extends React.Component {                    
    render() {                           
     return <button onClick={this.props.onAddTodo}>test</button>              
    }                              
}                               

class TodoItem extends React.Component {                     
    render() {                           
     return <span>item</span>                       
    }                              
}                               

let TodoList = ({items}) => (                       
    <ul>                             
     {items.map((item,index) =>                       
     <TodoItem key={index} index={index} message={item.message} completed={item.completed}/>       
    )}                             
    </ul>                             
)                               

let TodoComponent = ({ items, onAddTodo, onCompleteTodo, onDeleteTodo, onClearTodo }) => /* expand's props */    
    (                              
    <div>                             
     <h1>Todo</h1>                          
     <AddTodoForm onAddTodo={onAddTodo} message/>                  
     <TodoList items={items} onCompleteTodo={onCompleteTodo} onDeleteTodo={onDeleteTodo} onClearTodo={onClearTodo}/> 
    </div>                            
)                              

const mapStateToProps = (state) => {                      
    return {                            
     items: state.todo.items                       
    }                              
}                               

const mapDispatchToProps = (dispatch) => {                    
    return {                            
     onAddTodo(message) {                        
      dispatch(addTodo(message))                     
     },                            
     onCompleteTodo(index) {                       
      dispatch(completeTodo(index))                     
     },                            
     onDeleteTodo(index) {                        
      dispatch(deleteTodo(index))                     
     },                            
     onClearTodo(index) {                        
      dispatch(clearTodo(index))                     
     }                             
    }                              
}                               

var Wrapper = connect(mapStateToProps,mapDispatchToProps)(TodoComponent);             

render(                             
    <Provider store={store}>                        
     <Wrapper />                           
    </Provider>,                           
    document.getElementById('app')                       
) 
+0

私の減速家で私は新しいオブジェクトを作成しています。再度レンダリングする必要があるTodoListコンポーネントは、小道具が渡されたラップされたreduxコンポーネントの子です。レンダリングがトリガーされていない理由についての考えはありますか?ありがとう... –

+0

私の更新された答えを確認してください。 –

+0

Vladに感謝します。私は今、完全に新しいオブジェクトでなければならない新しい状態にtodoオブジェクト参照を渡していたことがわかります。それは今働いている。 –

関連する問題