Jake Giles-Phillips
Jake Giles-Phillips

Reputation: 188

React has detected a change in the order of Hooks called by Navigation

I'm really struggling to work out where my issue lies here, I have changed a lot of code recently and now I am met with this issue

   ERROR  Warning: React has detected a change in the order of Hooks called by Navigation. This will lead to bugs and errors if not fixed. For more information, read the Rules of Hooks: https://reactjs.org/link/rules-of-hooks

   Previous render            Next render
   ------------------------------------------------------
1. useContext                 useContext
2. undefined                  useRef
   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

    in Navigation (at App.tsx:96)
    in RCTView (at View.js:34)
    in View (at createAnimatedComponent.js:217)
    in AnimatedComponent (at createAnimatedComponent.js:278)
    in AnimatedComponentWrapper (at createAnimatableComponent.js:599)
    in withAnimatable(View) (at App.tsx:89)
    in App (at mobile/index.js:28)
    in HeadlessCheck (at renderApplication.js:47)
    in RCTView (at View.js:34)
    in View (at AppContainer.js:107)
    in RCTView (at View.js:34)
    in View (at AppContainer.js:134)
    in AppContainer (at renderApplication.js:40)

Presumably this is referring to my Navigation class, which I will share below, I am not particularly educated on the concept behind hooks and this issue is throwing me

import * as React from 'react';
import { View } from 'react-native';
import { NavigationContainer, NavigationContainerRef } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import { useStore } from '_src/store';
import { logScreenView } from '_utils/analytics';

import { SharedStackParamList } from './shared/SharedStack';
import { getSharedScreens } from './shared/Shared.screens';

import ErrorBoundary from '../components/atoms/ErrorBoundary';
import { modalOptions } from './StackOptions';
import { BLACK } from '_styles/colors';

const SharedStack = createStackNavigator<SharedStackParamList>();

export const Navigation = () => {
  const rootStore = useStore();
  const { authStore } = rootStore;
  if (authStore.token === undefined) return null;

  const routeNameRef = React.useRef<string>();
  const navigationRef = React.useRef<NavigationContainerRef>();

  function onReady() {
    routeNameRef.current = navigationRef.current.getCurrentRoute().name;
  }

  function onStateChange() {
    const previousRouteName = routeNameRef?.current;
    const currentRouteName = navigationRef?.current?.getCurrentRoute()?.name;

    if (previousRouteName !== currentRouteName) {
      logScreenView({ screen_name: currentRouteName, screen_class: currentRouteName });
      routeNameRef.current = currentRouteName;
    }
  }

  // Return main stack
  return (
    <View style={{ flex: 1, backgroundColor: BLACK, opacity: 1 }}>
      <ErrorBoundary>
        <NavigationContainer ref={navigationRef as any} onReady={onReady} onStateChange={onStateChange}>
          <SharedStack.Navigator screenOptions={modalOptions} mode="modal">
            {getSharedScreens().map(({ name, options, component }, i) => {
              // @ts-ignore
              return <SharedStack.Screen key={i} name={name} options={options} component={component} />;
            })}
          </SharedStack.Navigator>
        </NavigationContainer>
      </ErrorBoundary>
    </View>
  );
};

export default Navigation;

If anyone can help me understand hooks a bit better and help me out with this issue, would be greatly appreciated.

Upvotes: 4

Views: 11693

Answers (1)

Taxel
Taxel

Reputation: 4207

Check out the rules of hooks (page in the old React docs)

Hooks always need to be called in the same order (so adding new hooks conditionally is not allowed). Your code is breaking this rule, because you are using the useRef hooks after conditionally returning null.

The fix is very simple: Move the useRef usages above the if (authStore.token === undefined) return null; and you're good.

Upvotes: 11

Related Questions