1

The following code works as intended. The state gets populated using the createEntityAdapter.

import { createSlice, createAsyncThunk, createEntityAdapter } from '@reduxjs/toolkit';

export const fetchUsers = createAsyncThunk('users/fetchUsers', async () => {
  const response = await fetch('https://mysite/wp-json/wp/v2/users');
  return response.json();
});

export const usersAdapter = createEntityAdapter();
const initialState = usersAdapter.getInitialState({ status: 'idle' });

export const usersSlice = createSlice({
  name: 'users',
  initialState,
  reducers: {},
  extraReducers: (builder) => {
    builder.addCase(fetchUsers.pending, (state) => {
      state.status = 'pending';
    });
    builder.addCase(fetchUsers.fulfilled, usersAdapter.upsertMany);
  },
});

export default usersSlice.reducer;

However, with the fulfilled promise, I also want to update the 'status' property of the state to 'idle'.

When I change the fulfilled case to:

builder.addCase(fetchUsers.fulfilled, (state, action) => {
      usersAdapter.upsertMany;
      state.status = 'idle';
    });

And when I get add an argument the upsertMany

builder.addCase(fetchUsers.fulfilled, (state, action) => {
      usersAdapter.upsertMany(action.payload);
      state.status = 'idle';
    });

I get the error: Possible unhandled Promise Rejection (id: 0)

Apart from the question how to make it work, could I ask one additional question? In the first code snippet (That one that works):

builder.addCase(fetchUsers.fulfilled, usersAdapter.upsertMany);

I understand that the addCase has two arguments: action type/creator (fetchUsers.fulfilled is the action creator here), and a reducer (usersAdapter.upsertMany in this case). Here fetchUsers returns the object, but how does usersAdapter.upsertMany know what to insert/update as payload? There's no argument there (eg. usersAdapter.upsertMany(action.payload). In all other reducers requiring some payload, there's always an argument (state, action) eg.

builder.addCase(incrementBy, (state, action) => state.counter += action.payload)
Wasteland
  • 4,889
  • 14
  • 45
  • 91
  • What is `builder.addCase(fetchUsers.fulfilled, usersAdapter.upsertMany);` supposed to do? I think that is what is causing the issue. – yudhiesh Apr 28 '21 at 08:01
  • Another thing is that you should be setting the status to be `succeeded`, how would the component know when to render the users if you set it to `idle` ? – yudhiesh Apr 28 '21 at 08:13
  • @yudhiesh, that line is correct as per the official createAsyncThunk, createEntityAdapter documentation. It populates the normalized state. According to machine state paradigm, it should be 'idle', not 'succeed'. Anyway, it's the fulfiled path of createAsyncThunk so it knows it was successful – Wasteland Apr 28 '21 at 08:28
  • `upsertMany` expects `state` as first argument and `entities` as second – alextrastero Apr 29 '21 at 08:12
  • @alextrastero that's what I thought but how come then the first snippet works (without any argument) and the second doesn't? – Wasteland Apr 29 '21 at 19:46

0 Answers0