2016-09-13 5 views
2

Ich lerne React/Redux und kam zu einem Punkt, wo ich feststecke. In der Beispieltodo-App, an der ich arbeite, wenn eine neue Aufgabe hinzugefügt wird, wird die addTodo-Aktion ausgeführt und ich kann durch die store.dispatch-Logik gehen. Was fehlschlägt ist, dass der haveStatePropsChanged-Wert als false berechnet wird und daher keine untergeordneten Aktualisierungen vorgenommen werden.React/Redux nicht auslösendes Kind Render auf Status-Update

Die Code-Schnipsel folgen:

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); 

Die AddTodoForm richtig addTodo Aktion auslöst, ist die Frage der TodoList Komponente nicht wieder selbst Array durch die Elemente ist ein neues Array nicht machen.

UPDATE: Mein Reduzierer gibt einen neuen Status zurück.

Hier ist die Reduzierung und Aktionscode:

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 }; 

Danke,

Aaron

+0

Bitte fügen Sie Ihren Reducer-Code – Tyrsius

+0

hinzu, fügen Sie auch Ihre Aktionsmacher hinzu. – azium

+0

Lassen Sie es debuggen, können Sie eine console.log in den Reducer und in die Komponente setzen und die Ergebnisse veröffentlichen? Vielleicht stimmt etwas nicht mit der Benennung oder etwas ähnlichem (wenn du redux devtools installiert hast, ist es viel einfacher, das zu überprüfen) –

Antwort

2

Überprüfen Sie, ob Sie ein neues Objekt als ein Zustand in Ihrem Minderer zurückzukehren. Bsp .: return Object.assign ({}, state, {items: [...oldItems, newItem]})

Achten Sie hier [...oldItems, newItem] Dies wird neues Array erstellen. In Ihrem Fall macht Object.assign nur seichte Kopien und tatsächlich wurden Elemente geändert, die jedoch denselben Verweis enthalten. Sehen Sie sich das Arbeitsbeispiel an:

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

In meinem Reduzierer erstelle ich ein neues Objekt. Die TodoList-Komponente, die erneut gerendert werden muss, ist ein Kind einer eingepackten Redux-Komponente mit gerade übergebenen Requisiten. Gibt es irgendwelche Gedanken darüber, warum der Rendervorgang nicht ausgelöst wird? Danke ... –

+0

Überprüfen Sie bitte meine aktualisierte Antwort. –

+0

Danke Vlad. Ich sehe jetzt, dass ich die Todo-Objektreferenz in den neuen Zustand übergebe, wo es ein völlig neues Objekt sein sollte. Es funktioniert jetzt. –