Home > Net >  How to dispatch only after state initialization in redux
How to dispatch only after state initialization in redux

Time:11-12

Hello guys, sorry for my English it's my second language. So i have a Redux state which looks something like this:

const initialState = {
  user: null,
  isLoading: false,
};

And each time i load main screen(I'm using React Native), i take a user from local storage and put it in the state:

useEffect(() => {
    dispatch(getMe());
    dispatch(getCategories());
  }, []);

With a getMe function i take a user from local storage and with a getCategories one i make request to the api and get data. But if i would take a state value when getting categories, i get a null(default value):

// Get categories
export const getCategories = createAsyncThunk(
  "categories/get",
  async (_, thunkAPI) => {
    try {
      console.log(thunkAPI.getState().user.user);
      // The thunkAPI.getState().user.user value is null
      return await categoryService.getCategories();
    } catch (error) {
      thunkAPI.rejectWithValue(error);
    }
  }
);

I was just interested what would happen if i timeout getCategories function:

useEffect(() => {
    dispatch(getMe());
    setTimeout(() => dispatch(getCategories()), 1);
  }, []);

And it works. But i don't really think it's a good way to do that, So how do i fix this "properly"?

Previously thanks!!!

CodePudding user response:

You are not getting the updated value in async function because in react, updating state is asynchronous. You can get the updated state after react renders that component.

You can have two useEffects. In first useEffect, dispatch getMe function. This useEffect will run once. Then get the user value from store. Then in second useEffect, pass that state in dependency array. Now add a condition to check if user is not null, then dispatch getCategories function.

// Get The User Value From Store
const user = useSelector((state) => ...);

useEffect(() => {
    dispatch(getMe())
}, [])

useEffect(() => {
    if (user) { 
        dispatch(getCategories())
    }
}, [user])

CodePudding user response:

Just wait for getMe to be resolved before calling getCategories. No one guarantees you that getCategories will be resolved in n ms.

useEffect(() => {
    const getData = async () => {
      await dispatch(getMe()); // wait for the promise to resolve
      dispatch(getCategories());
    }
    getData();
  }, []);

Or you could also call getMe in your getCategories thunk:

export const getCategories = createAsyncThunk(
  "categories/get",
  async (_, thunkAPI) => {
    try {
      await thunkAPI.dispatch(getMe()); // wait for the promise to resolve
      console.log(thunkAPI.getState().user.user);
      // The thunkAPI.getState().user.user value is null
      return await categoryService.getCategories();
    } catch (error) {
      thunkAPI.rejectWithValue(error);
    }
  }
);

and just call getCategories in your component

// your component
useEffect(() => {
  dispatch(getCategories());
}, []);
  • Related