React 检测到 Navigation 调用的 Hook 顺序发生了变化

Jak*_*ips 3 javascript typescript reactjs react-native react-hooks

我真的很难弄清楚我的问题出在哪里,我最近更改了很多代码,现在遇到了这个问题

   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)
Run Code Online (Sandbox Code Playgroud)

大概这是指我的导航类,我将在下面分享,我对钩子背后的概念没有特别的了解,这个问题让我困惑

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;
Run Code Online (Sandbox Code Playgroud)

如果有人可以帮助我更好地理解钩子并帮助我解决这个问题,我将不胜感激。

Tax*_*xel 7

查看hooks 规则旧 React 文档中的页面

钩子总是需要以相同的顺序调用(因此不允许有条件地添加新钩子)。您的代码违反了此规则,因为您useRef在有条件返回 null 后使用了挂钩。

解决方法非常简单:将useRef用法移至上面if (authStore.token === undefined) return null;即可。