localdata01
localdata01

Reputation: 657

react redux how can I pass initialstate with functions?

I want to check the Key, if the key exists then I want to set the loggedIn in the initalstate to true. How can I do it? I get no error but my code not working.

import { createSlice } from '@reduxjs/toolkit';
import getSecureKey from '../../../utilies/getSecureKey';

const initialState = {
  process: false,
  loggedIn: getSecureKey().then(res => res).catch(e => e),
  message: '',
  error: '',
};
import * as SecureStore from 'expo-secure-store';

const getSecureKey = async () => {
  const key = await SecureStore.getItemAsync('jwt');
  return key != '' ? true : false
};

export default getSecureKey;

Upvotes: 1

Views: 1575

Answers (1)

Linda Paiste
Linda Paiste

Reputation: 42208

You cannot use asynchronous code in your initialState. What this actually does is set your state.loggedIn property to a Promise, so you should be getting warnings from redux-toolkit about storing non-serializable values in state.

It takes a moment for the getSecureKey() function to resolve. But the createStore/configureStore function is synchronous and cannot wait for the resolution.

You have two options.

  1. You can wait for getSecureKey() to resolve before creating the store. Your entire app can't really do anything until the store is created to you would have to render a loading screen instead, similar to what redux-persist does with the PersistGate component. I don't recommend this.

  2. You can dispatch an action to update the loggedIn state after the getSecureKey() function has finished resolving. You could set the initial value of state.loggedIn to false, but I actually recommend using null or undefined as a third option which tells you that you don't know yet whether the user is logged in or not. You can use a hook to handle the dispatch from your top-level App component. You can use an async thunk as an action creator to automatically handle errors.

Initial state:

const initialState = {
  process: false,
  loggedIn: null,
  message: '',
  error: '',
};

Action creator:

export const getInitialKey = createAsyncThunk(
  "someActionName",
  async () => {
    return await getSecureKey();
  }
)

In your slice:

extraReducers: {
  [getInitialKey.fulfilled]: (state, action) => {
    state.loggedIn = action.payload;
  },
  [getInitialKey.rejected]: (state, action) => {
    state.loggedIn = false;
  }
}

Auto-dispatch with hook:

const useGetSecureKey = () => {
  // we know that a key was received if the state isn't null
  const didAttempt = useSelector(state => state.mySlice.loggedIn !== null);

  const dispatch = useDispatch();

  // dispatches when the state is null
  // you could also use an empty dependency array and it's basically the same
  useEffect( () => {
    if ( ! didAttempt ) {
      dispatch(getInitialKey());
    }
  }, [didAttempt, dispatch]);
}

Upvotes: 1

Related Questions