React reacts to state changes differently than Redux


Gerriott

I've been scratching my brain with this for a while now, any help would be greatly appreciated.

I'm using React with the Redux Toolkit and I'm having trouble getting React to remove "todos" from my UI even though Redux responds as expected. In Redux Developer Tools, removeTodo works as expected, removing a todo item from the todos array state, but React doesn't follow it, so my UI doesn't change with it. My addTodo action works as expected in both React and Redux.

My current code gives me the following error when I click the button that calls the removeTodo dispatch.

TypeError: Cannot read property 'length' of undefined
App
C:/Users/joeee/Documents/redux-middleware/src/app/App.js:13
  10 | 
  11 |  return (
  12 |    <div style={divStyles}>
> 13 |      <TodosForm />
     | ^  14 |      {todos.length > 0 && <TodoList />}
  15 |    </div>
  16 |  )
View compiled
▶ 19 stack frames were collapsed.

It should be noted that I only render in my TodoList component when the length of my todos array state is > 0, as I don't want the component to be rendered without todos. I'm new to React and Redux and there may be a very simple solution, but as far as I know, when removeTodo is called, the todos array state is completely removed, not just returning those id's that are not equal to the id passed in . That's why I'm assuming the error I'm getting is telling me it can't read .length of undefined because my todos state is now empty.

I removed the requirement that todos.length needs to be greater than 0 to render the TodoList, but then I got the error that it couldn't read the .map that is not defined (my todo state) in the TodoList, which reinforced me The entire todo state appears to be being deleted.

Here is my todosSlice:

import { createSlice } from '@reduxjs/toolkit';

export const todosSlice = createSlice({
  name: 'todos',
  initialState: {
    todos: [],
  },
  reducers: {
    addTodo: (state, action) => {
      const { id, task } = action.payload; 

      state.todos.push({ id, task })
    },
    removeTodo: (state, action) => {
      // console.log(state.todos);

      const { id } = action.payload; 
      // console.log(id);
      
      return state.todos.filter(item => item.id !== id);
      
    }
  },
});

export const selectTodos = state => state.todos.todos; 

export const { addTodo, removeTodo } = todosSlice.actions; 
export default todosSlice.reducer; 

app.js:

import React from 'react';
import { useSelector } from 'react-redux'; 
import TodosForm from '../components/TodosForm';
import TodoList from '../components/TodoList';
import { selectTodos } from '../features/todosSlice';

export const App = () => {
  const todos = useSelector(selectTodos);
  // console.log(todos.length);

  return (
    <div style={divStyles}>
      <TodosForm />
      {todos.length > 0 && <TodoList />}
    </div>
  )
}

export default App;

TodoList.js

import React from 'react';
import { useSelector } from 'react-redux';
import { selectTodos } from '../features/todosSlice';
import Todos from './Todos';

const TodoList = () => {

  const todos = useSelector(selectTodos);
  // console.log(todos);

  return (
    <div style={divStyles}>
      <h3 style={headerStyles}>Your Todos: </h3>
      
      {todos.map(todo => <Todos key={todo.id} task={todo.task} id={todo.id} />)}
    </div>
  )
}

export default TodoList

all.js

import React from 'react';
import { useDispatch } from 'react-redux'; 
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faTrashAlt } from '@fortawesome/free-solid-svg-icons'
import { faEdit } from '@fortawesome/free-solid-svg-icons'
import { removeTodo } from '../features/todosSlice';

const Todos = ({ task, id }) => {
  const dispatch = useDispatch();

  const handleDeleteClick = () => {
    dispatch(removeTodo({id: id}));
  }

  return (
    <div style={divStyles}>
      <li style={listStyles}>{task}</li>
      <div>
        <button className="faEditIcon" style={btnStyles}><FontAwesomeIcon icon={faEdit}/></button>
        <button className="faDeleteIcon" style={btnStyles} onClick={handleDeleteClick}><FontAwesomeIcon icon={faTrashAlt}/></button>
      </div>
    </div>
  )
}

export default Todos;

and my store.js

import { configureStore } from '@reduxjs/toolkit'; 
import todosSliceReducer from '../features/todosSlice'; 

export default configureStore({
  reducer: {
    todos: todosSliceReducer,
  },
});
Anthony

You can update removeTodo as follows and see.

removeTodo: (state, action) => {
      // console.log(state.todos);

      const { id } = action.payload; 
      // console.log(id);
      
state.todos = state.todos.filter(item => item.id !== id)
      
    }

Related


React Redux state changes

illusory this.props.authStateremains the same, although I dispatch an action in the componentDidMountfunction : componentDidMount() { if (localStorage.getItem('token')) { dispatch(updateAuthState('AUTHENTICATED')); } } render() { <div>{

React Redux state changes

illusory this.props.authStateremains the same, although I dispatch an action in the componentDidMountfunction : componentDidMount() { if (localStorage.getItem('token')) { dispatch(updateAuthState('AUTHENTICATED')); } } render() { <div>{

React Redux state changes

illusory this.props.authStateremains the same, although I dispatch an action in the componentDidMountfunction : componentDidMount() { if (localStorage.getItem('token')) { dispatch(updateAuthState('AUTHENTICATED')); } } render() { <div>{

React Native with Redux: state changes not showing in console

Eliot When I put statements console.log('test')in the reducer, I can see them in the console when the action is called. But I don't see the redux "NEXT STATE"/"PREV STATE" stuff in the console. Is there any basic knowledge I might be missing? In the code below

React Redux store state changes not working

John Du The super simple code below is not working. I'm using React and injecting/providing props through a redux store. My understanding is to store injected props in React components. Why do I need both line1 and line 2 in order for this component to work? i

React Native with Redux: state changes not showing in console

Eliot When I put statements console.log('test')in the reducer, I can see them in the console when the action is called. But I don't see the redux "NEXT STATE"/"PREV STATE" stuff in the console. Is there any basic knowledge I might be missing? In the code below

React Native with Redux: state changes not showing in console

Eliot When I put statements console.log('test')in the reducer, I can see them in the console when the action is called. But I don't see the redux "NEXT STATE"/"PREV STATE" stuff in the console. Is there any basic knowledge I might be missing? In the code below

React Redux store state changes not working

John Du The super simple code below is not working. I'm using React and injecting/providing props through a redux store. My understanding is to store injected props in React components. Why do I need both line1 and line 2 in order for this component to work? i

React Native with Redux: state changes not showing in console

Eliot When I put statements console.log('test')in the reducer, I can see them in the console when the action is called. But I don't see the redux "NEXT STATE"/"PREV STATE" stuff in the console. Is there any basic knowledge I might be missing? In the code below

React Native with Redux: state changes not showing in console

Eliot When I put statements console.log('test')in the reducer, I can see them in the console when the action is called. But I don't see the redux "NEXT STATE"/"PREV STATE" stuff in the console. Is there any basic knowledge I might be missing? In the code below

React Redux store state changes not working

John Du The super simple code below is not working. I'm using React and injecting/providing props through a redux store. My understanding is to store injected props in React components. Why do I need both line1 and line 2 in order for this component to work? i

React Redux store state changes not working

John Du The super simple code below is not working. I'm using React and injecting/providing props through a redux store. My understanding is to store injected props in React components. Why do I need both line1 and line 2 in order for this component to work? i

React-Native reacts differently when not remote debugging

Saravanabalagi Ramachandran <Text style={s.date}>{ new Date(this.props.order.ordered_at).toLocaleDateString('en-US', { day: '2-digit', month: 'short' }) }</Text> <Text style={s.time}>({ new Date(this.props.order.ordered_at).toLocaleTimeString('en-US', { hour:

React-Native reacts differently when not remote debugging

Saravanabalagi Ramachandran <Text style={s.date}>{ new Date(this.props.order.ordered_at).toLocaleDateString('en-US', { day: '2-digit', month: 'short' }) }</Text> <Text style={s.time}>({ new Date(this.props.order.ordered_at).toLocaleTimeString('en-US', { hour:

React-Native reacts differently when not remote debugging

Saravanabalagi Ramachandran <Text style={s.date}>{ new Date(this.props.order.ordered_at).toLocaleDateString('en-US', { day: '2-digit', month: 'short' }) }</Text> <Text style={s.time}>({ new Date(this.props.order.ordered_at).toLocaleTimeString('en-US', { hour:

React-Native reacts differently when not remote debugging

Saravanabalagi Ramachandran <Text style={s.date}>{ new Date(this.props.order.ordered_at).toLocaleDateString('en-US', { day: '2-digit', month: 'short' }) }</Text> <Text style={s.time}>({ new Date(this.props.order.ordered_at).toLocaleTimeString('en-US', { hour:

React-Native reacts differently when not remote debugging

Saravanabalagi Ramachandran <Text style={s.date}>{ new Date(this.props.order.ordered_at).toLocaleDateString('en-US', { day: '2-digit', month: 'short' }) }</Text> <Text style={s.time}>({ new Date(this.props.order.ordered_at).toLocaleTimeString('en-US', { hour: