Home > database >  Why is state.filter in Redux Toolkit not filtering the array?
Why is state.filter in Redux Toolkit not filtering the array?

Time:12-12

I'm creating a goal tracker with Redux Toolkit for learning purposes. The goals are held in an array which I push new values to with no issues, but when I try to state.filter the same array, the value isn't removed. Redux devtools shows deleteGoal running, but it's not deleting anything.

I tried using splice, filtering current(state), logging state, and placing debuggers throughout the various files. I noticed that state logs as a proxy, but if that were the problem, why does state.push() work and state.filter() doesn't?

The array (in the slice):

const initialState = [
    {
        id: 1,
        input: 'drink water',
        achieved: true
    },
    {
        id: 2,
        input: 'in bed by 11:15',
        achieved: true
        },
    {
        id: 3,
        input: 'study 2hrs',
        achieved: true
    },
]

The actions:

export const goalsSlice = createSlice({
  name: 'goals',
  initialState,
  reducers: {
    addGoal: (state, action) => {
        state.push(action.payload)
      },
    deleteGoal: (state, action) => {
      const goalId = action.payload
      state.filter((goal) => goal.id !== goalId)
      console.log(current(state))
    },
  },
})

The component where it's rendered:

<Text
        fontSize="3xl"
        fontWeight={600}
        >your goals:</Text>
            {goals.map((goal, index) => (
                    <li 
                    key={index}
                    onDoubleClick = {goal => {
                        dispatch(deleteGoal(goal.target.textContent))
                        // console.log(goal)
                        // console.log(goal.target.textContent)
                    }}
                    className='goal-text'
                    >
                        
                        {goal.input}
                    </li> 
            
        ))}

CodePudding user response:

state.filter() is not working as you expect because you need to return the result in order to update the state; not change it in place. e.g.

return state.filter((goal) => goal.id !== goalId)

state.push() does work as you expect because it's changing the state in-place as opposed to returning a value. This is arguably against the best practice of Redux - your addGoal function could be changed to something like

addGoal: (state, action) => {
  // return a new array, don't modify the existing state in place
  return [
    ...state, // copy the current array of goals
    (action.payload) // add the new goal
  ]
},

See https://redux.js.org/style-guide/#do-not-mutate-state for more details

CodePudding user response:

Because filter() does not modify the array, rather it creates a shadow copy of it, perhaps the intended action in deleteGoal should be:

// Only for redux-toolkit

state = state.filter((goal) => goal.id !== goalId)

According to redux-toolkit document (as opposed to Redux):

To make things easier, createReducer uses immer to let you write reducers as if they were mutating the state directly. In reality, the reducer receives a proxy state that translates all mutations into equivalent copy operations.

More examples about how redux-toolkit allows "mutating" update of immutable state in reducers for: createSlice.

  • Related