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
.