Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to update nested objects in Redux toolkits?

My initialState look like below:

const initialState: Todos = {
  todos: [
    {
      id: 1,
      completed: true,
      title: "setup redux",
      note: "test1",
      steps: [
        { id: 1, completed: true, title: "test2" },
        { id: 2, completed: false, title: "test2" }
      ]
    },
    {
      id: 2,
      completed: false,
      title: "using redux on typescript",
      note: "test3"
    }
  ]
};

So right now my problem is how do I update "step" property in Redux toolkit? I have done some research know there's a way to update nested objects by destructing my objects, but the thing is that if I want to update my "step" property, I have to know todo[id] and steps[id] to destruct my objects, but I think redux is not allowed to pass two action.payload at a time, so I wonder how to do this.

For other CRUD actions like delete and add , I create a new Todo and used updateTodo like below,but because I can't alter what's inside state without dispatch so I can't use this method to update steps (some update like toggle), and also I don't think this is a good idea for replacing nested objects.

//Redux-todoSlice.tsx
updateTodo : (state,action:PayloadAction<Todo>)=>{
      state.todos = state.todos.map( (todo)=>
        todo.id === action.payload.id ? action.payload : todo
      )
    }

//------------In my components

const Rightbar: React.FC<rightbarProps> = ({ currentTodoId }) => {
const todos  = useSelector((state:RootState)=>
    state.todo.todos.filter((todo=>todo.id === currentTodoId))
);
 const currentTodo = todos[0]
#....somecode
const deleteStep = (id:number)=>{

     if (currentTodo.steps!==undefined){
      const newSteps = currentTodo?.steps.filter((step)=> step.id!==id)
      const newTodo:Todo = {...currentTodo,steps:newSteps}
      dispatch(updateTodo(newTodo)) 
     }
  }

So do anyone know is there a better approach for this?

like image 222
Kai021195 Avatar asked Sep 06 '25 07:09

Kai021195


1 Answers

You can use an object with multiple properties as payload.

You would do something like

completeStep(state, action: PayloadAction<{ todoId: string, stepId: string }>) {
  const todo = state.todos.find(todo => todo.id == payload.action.todoId)
  if (todo) {
    const step = todo.steps.find(step => step.id == payload.action.stepId);
    if (step) {
      step.completed = true
    }
  }
}

Further reading: https://redux-toolkit.js.org/usage/immer-reducers

like image 62
phry Avatar answered Sep 07 '25 22:09

phry