1

I was tasked to maintain an expo application which was in a pretty bad state. It was using react-native 0.62.2. I built the application using the old react version, the application was running successively but had issues with its android build, so I decided to migrate the application to react-native 0.71.3 by initializing an empty expo project and copying the source files to the directory. Then, I installed all the dependencies manually using

npx expo install [package-name]

When I start the application using

npx expo start

I get

Cannot read property 'useState' of null

with the first call to useState().

Here are the source files: [old-package.json]

{
  "scripts": {
    "start": "react-native start",
    "android": "react-native run-android",
    "ios": "react-native run-ios",
    "web": "expo start --web",
    "eject": "expo eject"
  },
  "dependencies": {
    "@react-native-community/checkbox": "^0.5.5",
    "@react-native-community/datetimepicker": "^2.4.0",
    "@react-native-community/masked-view": "^0.1.10",
    "@react-native-community/picker": "1.6.0",
    "@react-native-firebase/app": "^10.3.0",
    "@react-native-firebase/auth": "^10.3.1",
    "@react-navigation/bottom-tabs": "^5.9.1",
    "@react-navigation/drawer": "^5.9.2",
    "@react-navigation/material-bottom-tabs": "^5.2.18",
    "@react-navigation/native": "^5.7.5",
    "@react-navigation/stack": "^5.9.2",
    "abort-controller": "^3.0.0",
    "apisauce": "^1.1.2",
    "aws-sdk": "^2.784.0",
    "axios": "^0.21.0",
    "base64-arraybuffer": "^0.2.0",
    "expo": "~38.0.8",
    "expo-crypto": "~8.2.1",
    "expo-document-picker": "~8.2.1",
    "expo-file-system": "~9.0.1",
    "expo-font": "~8.2.1",
    "expo-image-picker": "~8.3.0",
    "expo-localization": "~8.2.1",
    "expo-secure-store": "~9.0.1",
    "expo-splash-screen": "^0.5.0",
    "expo-status-bar": "^1.0.2",
    "expo-updates": "~0.2.10",
    "formik": "^2.2.5",
    "i18n-js": "^3.7.1",
    "js-base64": "^3.5.2",
    "jwt-decode": "^3.0.0-beta.2",
    "native-base": "^2.13.14",
    "react": "~16.11.0",
    "react-aws-s3": "^1.3.0",
    "react-dom": "~16.11.0",
    "react-hook-form": "^6.11.3",
    "react-native": "~0.62.2",
    "react-native-base64": "^0.2.1",
    "react-native-check-box": "^2.1.7",
    "react-native-datepicker": "^1.7.2",
    "react-native-form-validator": "^0.3.5",
    "react-native-fs": "^2.16.6",
    "react-native-gesture-handler": "~1.6.0",
    "react-native-keyboard-aware-scroll-view": "^0.9.3",
    "react-native-loading-spinner-overlay": "^1.1.0",
    "react-native-material-dropdown": "^0.11.1",
    "react-native-modal-selector": "^2.0.3",
    "react-native-paper": "^4.2.0",
    "react-native-razorpay": "^2.2.2",
    "react-native-reanimated": "~1.9.0",
    "react-native-s3-upload": "0.0.12",
    "react-native-safe-area-context": "~3.0.7",
    "react-native-screens": "~2.9.0",
    "react-native-splash-screen": "^3.2.0",
    "react-native-swipe-gestures": "^1.0.5",
    "react-native-table-component": "^1.2.1",
    "react-native-unimodules": "~0.10.1",
    "react-native-upload-aws-s3": "^0.8.1",
    "react-native-validation": "^1.0.3",
    "react-native-validator-form": "^1.0.0",
    "react-native-web": "~0.11.7",
    "react-navigation-stack": "^2.8.2",
    "react-s3": "^1.3.1",
    "validate.js": "^0.13.1",
    "yup": "^0.29.3"
  },
  "devDependencies": {
    "@babel/core": "^7.8.6",
    "babel-jest": "~25.2.6",
    "babel-preset-expo": "~8.1.0",
    "jest": "~25.2.6",
    "react-test-renderer": "~16.11.0"

[new package.json]

{
  "name": "sathee-reboot",
  "version": "1.0.0",
  "main": "node_modules/expo/AppEntry.js",
  "scripts": {
    "start": "expo start",
    "android": "expo start --android",
    "ios": "expo start --ios",
    "web": "expo start --web"
  },
  "dependencies": {
    "@expo/vector-icons": "^13.0.0",
    "@react-native-community/datetimepicker": "6.7.3",
    "@react-native-masked-view/masked-view": "^0.2.8",
    "@react-native-picker/picker": "^2.4.8",
    "@react-navigation/bottom-tabs": "^6.5.7",
    "@react-navigation/drawer": "^6.6.2",
    "@react-navigation/material-bottom-tabs": "^6.2.15",
    "@react-navigation/native": "^6.1.6",
    "@react-navigation/stack": "^6.3.16",
    "apisauce": "^2.1.6",
    "axios": "^1.3.4",
    "babel-plugin-module-resolver": "^5.0.0",
    "babel-preset-expo": "^9.3.0",
    "base64-arraybuffer": "^1.0.2",
    "expo": "~48.0.4",
    "expo-app-loading": "^2.1.1",
    "expo-constants": "~14.2.1",
    "expo-crypto": "~12.2.1",
    "expo-document-picker": "~11.2.1",
    "expo-font": "~11.1.1",
    "expo-image-picker": "~14.1.1",
    "expo-localization": "~14.1.1",
    "expo-secure-store": "~12.1.1",
    "expo-status-bar": "~1.4.4",
    "formik": "^2.2.9",
    "i18n-js": "^4.2.2",
    "js-base64": "^3.7.5",
    "jwt-decode": "^3.1.2",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-hook-form": "^7.43.2",
    "react-native": "^0.71.3",
    "react-native-base64": "^0.2.1",
    "react-native-check-box": "^2.1.7",
    "react-native-datepicker": "^1.7.2",
    "react-native-keyboard-aware-scroll-view": "^0.9.5",
    "react-native-loading-spinner-overlay": "^3.0.1",
    "react-native-modal-selector": "^2.1.2",
    "react-native-paper": "^5.2.0",
    "react-native-razorpay": "^2.3.0",
    "react-native-reanimated": "~2.14.4",
    "react-native-s3-upload": "^0.0.12",
    "react-native-swipe-gestures": "^1.0.5",
    "react-native-table-component": "^1.2.2",
    "react-native-validator-form": "^1.0.0",
    "yup": "^1.0.2"
  },
  "devDependencies": {
    "@babel/core": "^7.20.0"
  },
  "private": true
}

[App.js]

import React,{useState,useEffect} from 'react';
import { NavigationContainer } from '@react-navigation/native';
import AuthNavigator from './app/navigations/AuthNavigator' ;
import CustomerNavigator from './app/navigations/CustomerNavigator'
import ClientNavigator from './app/navigations/ClientNavigation'

import AuthContext from './app/auth/context';
import authStorage from './app/auth/authStorage';
import userStorage from './app/auth/userStorage'

import jwtDecoder from 'jwt-decode';
import { Provider as PaperProvider } from 'react-native-paper';
import {AppLoading} from 'expo'
import CustomerAsClient from './screen/CustomerAsClient'
import * as Font from 'expo-font';
import 'react-native-gesture-handler';
import Splash from './screen/Splash'
const fetchFonts = () => {
  return Font.loadAsync({
  'roboto-bold' :    require('./app/assets/fonts/Roboto-Bold.ttf'),
  'roboto-italic' :  require('./app/assets/fonts/Roboto-Italic.ttf'),
  'roboto-regular' : require('./app/assets/fonts/Roboto-Regular.ttf')
  });
  };


function App() {
  console.log("Reached checkpoint: 1");
  const [user, setUser] = useState(null);// Application crashes here
  console.log("Reached checkpoint: 2");
  const [language, setLanguage] = useState('en') //set
  const [userName, setUserName] = useState(null)   
  const [isReady, setisReady] = useState(false)
  const [wasLoggedIn, setwasLoggedIn] = useState(false)
  const [userRole, setuserRole] = useState()
  const [fontLoaded, setfontLoaded] = useState(false)

    const getToken = async () => { 
        await fetchFonts();
        const token = await authStorage.getToken();
        const userData = await userStorage.getUser();
        if(!token) return;
        const tokenDecoded = jwtDecoder(token);
        const DecodeduserData = JSON.parse(userData)
        setUserName(DecodeduserData.firstName);
        setuserRole(DecodeduserData.userRole.roleId)
        console.log(DecodeduserData)
    }
    if(!isReady)
        return <AppLoading startAsync={getToken}  onFinish={()=> setisReady(true)}/>   
    return (
        <AuthContext.Provider value ={{user, setUser,
                                       language, setLanguage,
                                       setUserName, userName,
                                       setwasLoggedIn, wasLoggedIn,
                                       setuserRole}}>
            <PaperProvider>      
                <NavigationContainer >
                    {  
                        user || userName ? 
                            userRole == '1'  ?  <CustomerNavigator/>  :
                            userRole == '2' ? <ClientNavigator/>  :
                            userRole == '4' ? <CustomerAsClient /> : 
                            <AuthNavigator/>    
                        :  <AuthNavigator/>            
                    }  
                </NavigationContainer>
            </PaperProvider>
        </AuthContext.Provider>
    );
};

export default App();

So far I've tried everything listed here, deleted node-modules reinstalled then using npx expo install. Uninstalled all packages and reinstalled them using --save flag as mentioned here. The issue persists.

Moritz Ringler
  • 9,772
  • 9
  • 21
  • 34
Caesar
  • 11
  • 1
  • https://stackoverflow.com/questions/72413194/uncaught-typeerror-cannot-read-properties-of-null-reading-usecontext/73981865#73981865 does this answer you question – krishnaacharyaa Mar 01 '23 at 07:21
  • Tried deleting node-modules and package.lock, still no luck. – Caesar Mar 01 '23 at 10:06

1 Answers1

0

I think it's because of the async function, the page renders first by that the function doesn't finish so the state is still null. Try putting setState or the entire function inside useEffect and this might solve the issue.On the state change of isReady the page will rerender so I think it will work.

function App() {
    console.log("Reached checkpoint: 1");
    const [user, setUser] = useState(null);// Application crashes here
    console.log("Reached checkpoint: 2");
    const [language, setLanguage] = useState('en') //set
    const [userName, setUserName] = useState(null)   
    const [isReady, setisReady] = useState(false)
    const [wasLoggedIn, setwasLoggedIn] = useState(false)
    const [userRole, setuserRole] = useState()
    const [fontLoaded, setfontLoaded] = useState(false)
  
    useEffect(()=>{
        getToken();
    },[])

    const getToken = async () => { 
          await fetchFonts();
          const token = await authStorage.getToken();
          const userData = await userStorage.getUser();
          if(!token) return;
          const tokenDecoded = jwtDecoder(token);
          const DecodeduserData = JSON.parse(userData)
          setUserName(DecodeduserData.firstName);
          setuserRole(DecodeduserData.userRole.roleId)
          console.log(DecodeduserData)

          setisReady(true);

      }
      if(!isReady)
          return <AppLoading >   
      return (
          <AuthContext.Provider value ={{user, setUser,
                                         language, setLanguage,
                                         setUserName, userName,
                                         setwasLoggedIn, wasLoggedIn,
                                         setuserRole}}>
              <PaperProvider>      
                  <NavigationContainer >
                      {  
                          user || userName ? 
                              userRole == '1'  ?  <CustomerNavigator/>  :
                              userRole == '2' ? <ClientNavigator/>  :
                              userRole == '4' ? <CustomerAsClient /> : 
                              <AuthNavigator/>    
                          :  <AuthNavigator/>            
                      }  
                  </NavigationContainer>
              </PaperProvider>
          </AuthContext.Provider>
      );
  };
  
  export default App();
  
dk_1999
  • 1
  • 1
  • Still the error persists `TypeError: Cannot read property 'useState' of null, js engine: hermes`. – Caesar Mar 01 '23 at 10:03
  • kindly refer to this article, it's about using async functions with useEffect hook https://devtrium.com/posts/async-functions-useeffect – dk_1999 Mar 02 '23 at 05:17
  • Thanks, I've read the article; changed the `useEffect` portion to [this](https://codefile.io/f/nzenXiDWHC3i1Nb6etd0). Still getting `TypeError: Cannot read property 'useState' of null, js engine: hermes.`. – Caesar Mar 02 '23 at 06:32
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Mar 05 '23 at 14:33