簡體   English   中英

React/Redux 不會在狀態更新時觸發子渲染

[英]React/Redux not triggering child render on state update

我正在學習 React/Redux 並且遇到了卡住的地步。 在示例待辦事項應用程序中,當添加新的待辦事項時,我正在處理 addTodo 操作,我可以逐步執行 store.dispatch 邏輯。 失敗的是 hasStatePropsChanged 值計算為 false 因此沒有子更新。

代碼片段如下:

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 操作,問題是即使 items 數組是一個新數組,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 };

謝謝,

亞倫

檢查您是否在減速器中返回了一個新對象作為狀態。 例如: 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')                                                                                         
)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM