2016-09-13 57 views
2

我正在學習React/Redux,並且遇到了卡住的問題。在我正在處理的示例待辦事項應用中,當添加新的待辦事項時,會執行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的分量甚至不通過的項目陣列再次渲染是一個新的數組。

更新: 我的reducer確實返回一個新的狀態。

這裏是減速和動作代碼:

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放入reducer和組件併發布結果?也許在命名或類似的東西是錯誤的(如果你已經安裝了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

在我的reducer中,我創建了一個新的對象。需要再次渲染的TodoList組件是帶有剛剛傳入的道具的已包裝的redux組件的子項。有關爲什麼渲染未被觸發的任何想法?謝謝... –

+0

請檢查我更新的答案。 –

+0

謝謝弗拉德。我現在看到,我正在將待辦事項對象引用傳遞給它應該是一個全新對象的新狀態。它正在工作。 –

相關問題