4

I have seen a lot of SO/github issues with this title, and I'm sure that actually did not do what causes this error 99% of the time: -connect wrapper component with MapStateToProps and MapDispatchToProps, -return new State instead of mutating actual state in reducer.

In the redux devtools extension, I can see the StoreState changing with the new Todo in the list when I dispatch a ADD_TODO. When I dispatch a ADD_TODO, Body component is not re-rendered. If I inject a Todo in the todos initial StoreState, The Todo is displayed in the Body Component.

You can find the repository here

reducer :

import { TodoAction } from '../actions';
import { StoreState } from '../types/index';
import { ADD_TODO, TOGGLE_TODO } from '../constants/index';
import TodoModel from '../models/TodoModel';

export function todos(state: StoreState, action: TodoAction): StoreState {
    let todos: Array<TodoModel>;
    switch (action.type) {
        case ADD_TODO:
            todos = state.todos;
            todos.unshift(action.todo);
            return { ...state, todos: todos };
        case TOGGLE_TODO:
            todos = state.todos;
            const todo = todos.find(todo => todo.id === action.todo.id);
            if (todo !== undefined) {
                const key = todos.indexOf(todo);
                todos[key].done = true;
            }
            return { ...state, todos: todos };
        default:
            return state;
    }
}

Container component:

export default connect(mapStateToProps, mapDispatchToProps)(Body);
import Body from '../components/Body/Body';
import { StoreState } from '../types/index';
import { connect } from 'react-redux';

export function mapStateToProps({ todos }: StoreState) {
    return {
        todos
    };
}

export function mapDispatchToProps() {
    return {
        //
    };
}
export default connect(mapStateToProps, mapDispatchToProps)(Body);

Component not updated by storeState changes :

import * as React from 'react';
import TodoModel from '../../models/TodoModel';

interface Props {
    todos: Array<TodoModel>;
}

interface State {

}

class Body extends React.Component<Props, State> {

    constructor(props: Props) {
        super(props);
    }

    render() {
        console.log(this.props);
        return (
            <div>
                <ul>
                    {this.props.todos.map(todo => <li key={todo.id}>{todo.content}</li>)}
                </ul>
            </div>
        );
    }
}

export default Body;

1 Answer 1

6

unshift mutates the array, you need to return a new one:

case ADD_TODO:
    todos = [...state.todos]; // or - state.todos.slice();
    todos.unshift(action.todo);
    return { ...state, todos: todos };
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks, thats it.
@CTaque sure. If I helped please upvote or accept the answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.