Reputation: 188
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
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