【问题标题】:React has detected a change in the order of Hooks called by NavigationReact 检测到 Navigation 调用的 Hooks 的顺序发生了变化
【发布时间】:2021-11-05 04:07:41
【问题描述】:

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

   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)

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

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;

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

【问题讨论】:

    标签: javascript reactjs typescript react-native react-hooks


    【解决方案1】:

    查看rules of hooks

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

    解决方法非常简单:将 useRef 的用法移到 if (authStore.token === undefined) return null; 上方就可以了。

    【讨论】:

    • 难以置信...谢谢你,为了链接那个页面,我会好好整理自己,这样我以后就可以避免这样的愚蠢事情了!
    • 我遇到了同样的钩子错误,因为我在导航栏中有条件地渲染了 2 个按钮中的 1 个(“登录”或“注销”)。如果登录时我移动到另一个屏幕,返回然后注销,则会触发错误。我发现我必须在我的 LogoutButton 组件中调用我在 LoginButton 组件中调用的钩子,即使我没有使用它——但是,这确实解决了我遇到的错误。谢谢!
    猜你喜欢
    • 2021-10-02
    • 1970-01-01
    • 2019-12-15
    • 2021-12-15
    • 2022-10-02
    • 2020-07-04
    • 1970-01-01
    • 2022-01-21
    • 1970-01-01
    相关资源
    最近更新 更多