3

I'm trying to create an object and add it to a reducer, but have the action/reducer take care of generating the id.

Per this answer, it seems the accepted pattern is to generate the id in the action creator:

const todosSlice = createSlice({
  name: "todos",
  initialState: [],
  reducers: {
    addTodo: {
      reducer(state, action) {
        state.push(action.payload);
      },
      prepare(text) {
        const id = uuid();
        return { payload: {text, id} };
      }
    }
  }
})

However, suppose I want to then use / refer to the id after creating the todo, something like

dispatch(addTodo('Say hello world')) // creates a todo with a uuid
...
id = <some way to get the id>
doSomethingElseWithTodoGivenId()

Does Redux-Toolkit provide any assistance with achieving this? I looked at createAsyncThunk, but that appears to be more focussed around async data fetching status.

I know I can do this with redux-thunk (by awaiting the dispatch and having the thunk action generate the id):

const id = await dispatch(createTodoWithGeneratedId('Say hello world'))

or by having the caller generate the id. But I'm wondering if there's a better way.

Yilmaz
  • 35,338
  • 10
  • 157
  • 202
Sherwin Yu
  • 3,180
  • 2
  • 25
  • 41

2 Answers2

0

Unfourtonately, dispatch is not working that way. Plain Redux dispatch call retuns a dispatched action, but redux-toolkit using thunk middleware by default that changes a dispatch returning value to promise that fullfiled with dispatched action. You can't get a result of dispatching result from dispatch call itself, it is impossible and conflicts with it's nature.

However, you can create a thunk that dispatches different actions based on promise result. Check official documentation about creating thunk with side effects. For more advanced usage check this answer in SO.

If you are using redux-toolkit, you can use createAsyncThunk, it is implements the same logic but without much more boilerplate code.

Mike Kokadii
  • 509
  • 5
  • 17
  • imo this reality is where RTK fails to me.. i originally liked handling api requests through thunk side effects, which added consistency to response middlewares (like handling authorization errors) but sometimes i want to make api requests and return those values to the component state... now i have to write a separate controller to handle those network request errors – Alec Mather Oct 12 '22 at 18:21
0

There is no accepted pattern in this case. Sometimes you have to figure out things based on your needs. That is why leetcode algorithms are such a big deal in hiring process.

If you follow your above implementation

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

  prepare(text) {
    const id = nanoid();
    return { payload: {text, id} };
  }

the only way to get the "id" is you have to get the state with the useSelector and then loop through where text===currentToDo. This is too much work for a simple task.

Instead, why not pass id with the dispatching? You arrange your payload where accepts an object. (Because you cannot pass multiple args)

const id=nanoid()
dispatch(addTodo({todo:'Say hello world',id:id}))
// now use that id todo something

in this scenario, you do not even need the prepare phase. (you did not before neither). just push the payload object to the array

Yilmaz
  • 35,338
  • 10
  • 157
  • 202