useReducer: Not able to get the initial state using userReducer

1.2k Views Asked by At

I have implemented useReducer to dispatch the action based on the action type and each time I'm updating a state variable based on the action type but always I'm getting an error while trying to read the initial state. Probably my code can explain more.

I'm getting the error when I'm trying to read initialLoginState.isLoading.

App.js code:

import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import BottomNavigation from './src/Navigations/BottomNavigation';
import AuthStackNavigation from './src/Navigations/AuthStackNavigation'
import { useState, useEffect, useMemo, useReducer } from 'react';
import { View } from 'react-native-animatable';
import { ActivityIndicator } from 'react-native';
import { AuthenticationContext } from './src/context/AuthenticationContext'

export default function App() {

  //Initial state values
  const initialLoginState = {
    isLoading: false,
    userName: null,
    userToken: null
  }

//Reducer function
  const loginReducer = (action, prevState) => {
    switch (action.type) {
      case 'LOGIN':
        return {
          ...prevState,
          userToken: action.token,
          userName: action.id,
          isLoading: false
        };
      case 'LOGOUT':
        return {
          ...prevState,
          userName: null,
          userToken: null,
          isLoading: false,
        };
      case 'REGISTER':
        return {
          ...prevState,
          userToken: action.token,
          userName: action.id,
          isLoading: false,
        };
      case 'RETRIEVE_TOKEN ':
        return {
          ...prevState,
          userToken: action.token,
          isLoading: false
        };
    }
  }

  //Defining useReducer
  const [newLoginState, dispatch] = useReducer(loginReducer, initialLoginState);
  const authContext = useMemo(() => ({
    signIn: (email, password) => {
      // setUserToken('abc');
      // setIsLoading(false);

      console.log("called")
      let userToken
      userToken = null;
      if (email == 'user' && password == 'pass') {
        userToken = 'abc';
      }
      dispatch({ type: 'RETRIEVE_TOKEN', id: email, token: userToken })
    },
    signOut: () => {
      dispatch({ type: 'LOGOUT', })
    },
    signUp: () => {
      setUserToken(null);
      setIsLoading(false);
    }

  }), []);

  useEffect(() => {
    let userToken;
    userToken = "dfsdfsdf"
    dispatch({ type: 'REGISTER', token: userToken })
  }, [])

  if (initialLoginState.isLoading) {
    return (
      <View style={{ flex: 1, justifyContent: 'center', alignContent: 'center' }}>
        <ActivityIndicator size='large'></ActivityIndicator>
      </View>
    )
  }

  return (
    <AuthenticationContext.Provider value={authContext}>
      <NavigationContainer>
        {initialLoginState.userToken !== null ?
          <BottomNavigation />
          :
          <AuthStackNavigation />
        }
      </NavigationContainer>
    </AuthenticationContext.Provider>

  );
}

Error:

TypeError: undefined is not an object (evaluating 'newLoginState.isLoading')
- node_modules/react-native/Libraries/LogBox/LogBox.js:148:8 in registerError
- node_modules/react-native/Libraries/LogBox/LogBox.js:59:8 in errorImpl
- node_modules/react-native/Libraries/LogBox/LogBox.js:33:4 in console.error
2

There are 2 best solutions below

3
On BEST ANSWER

try updating the reducer function to this (flipped the parameters!):

//Reducer function
//-  const loginReducer = (action, prevState) => {
  const loginReducer = (prevState, action) => {
    switch (action.type) {
      case 'LOGIN':
        return {
          ...prevState,
          userToken: action.token,
          userName: action.id,
          isLoading: false
        };
      case 'LOGOUT':
        return {
          ...prevState,
          userName: null,
          userToken: null,
          isLoading: false,
        };
      case 'REGISTER':
        return {
          ...prevState,
          userToken: action.token,
          userName: action.id,
          isLoading: false,
        };
      case 'RETRIEVE_TOKEN ':
        return {
          ...prevState,
          userToken: action.token,
          isLoading: false
        };
      default:
        return prevState;
    }
  }

dont forget the default case!

3
On

First, the default case in the reducer function's switch is missing!
Second, can you put the whole component code (just the needed part!) because I have no problem running your code even without the default case!