Home > Software engineering >  State will not Update when using createAsyncThunk and Redux Toolkit
State will not Update when using createAsyncThunk and Redux Toolkit

Time:12-07

When using createAsyncThunk to obtain data from my API, I can read the data, but the state will not update.

I created a slice in my file userSlice.js, like so

userSlice.js:

export const fetchUserById = createAsyncThunk(
  'user/fetchUserById',
  async (userId, thunkAPI) => {
    let response;
    try {
      response = await API.getUser, { userID: userId }));
    } catch (e) {
        console.log(e)
    }
    return response.data.getUser
  }
);

export const userSlice = createSlice({
  name: 'user',
  initialState: {user: {}},
  reducers: {},
  },
  extraReducers: (builder) => {
    builder.addCase(fetchUserById.fulfilled, (state, action) => {
      state = {
        ...state,
        user: action.payload
      }
    });
  }
});

export default userSlice.reducer

This is my store, store.js:

import { configureStore } from '@reduxjs/toolkit'
import userReducer from './slices/userSlice'

export default configureStore({
  reducer: {
    userReducer
  }
})

I try to read the data in AppLoadingScreen.js

AppLoadingScreen.js:

import AppLoading from 'expo-app-loading';
import React from 'react';
import { useSelector, useDispatch } from 'react-redux'
import { fetchUserById } from '../../redux/slices/userSlice';

const AppLoadingScreen = (props) => {
  const user = useSelector(state => state.userReducer.user)
  const dispatch = useDispatch()
  
  const cacheResources = async () => {
    dispatch(fetchUserById('00'))
      .unwrap()
      .then((result) => console.log("result: ", result))
      .then(console.log("in dispatch: ", user))
      .catch((e) => {console.log(e)});

    console.log("test: ", user);
  }

  return (
    <AppLoading
      startAsync={cacheResources}
      onFinish={() => {props.setIsReady(true)}}
      one rror={console.warn}
    />
  );
}

Output:

in dispatch:  Object {}
test:  Object {}
result:  Object {
  "firstName": "John",
  "lastName": "Doe",
  "height": 72,
  "age": 40,
}

In both cases, user does not update. Even if I change the dispatch call to instead use await, the state doesn't change. New dispatch call:

const cacheResources = async () => {
  await dispatch(fetchUserById('00'));
  
  console.log("test: ", user);
}

New output:

test:  Object {}

I have also tried running the dispatch call outside of Expo's AppLoading component and the result is still the same.

CodePudding user response:

state = in an RTK Immer-powered reducer is never correct. Immer works by tracking mutations to nested fields (state.someField =), or returning an entirely new value from the reducer function ( return newState). When you write state =, all that does is point the local variable named state at a new reference, which is neither a mutation nor returning anything.

So, as far as Immer can see, you haven't changed anything.

The simplest answer here is to write state.user = action.payload.

See RTK Usage Guides: Writing Reducers with Immer for more details.

Additionally, we specifically recommend not using the word "reducer" in your state structure. Instead, you should set up the store so that the state keys are named after the types of data, like:

configureStore({
  reducer: {
    user: userReducer
  }
})
  • Related