React (Native) Context API 导致 Stack Navigator (React Navigation 5) 在状态更新后重新渲染

React (Native) Context API Causes Stack Navigator (React Navigation 5) to re-render after state update

在此先感谢您帮助解决这个问题。


一些上下文(无双关语意)

我正在做一个公司的项目,这将限制我将所有代码放在这里,但我会尝试在不泄露国家机密的情况下尽可能多地放相关代码。

基本上,React Native 应用程序使用的是 React Navigation v5,我已经尝试解决这个问题两天了。我明白发生了什么,但我不明白为什么会发生或如何解决它。

在应用程序代码的某处,您有以下代码。

export const Lounge = function Lounge(props: {navigation: any}) {
  
  const {navigation: {setOptions}} = props
  const bottomTabBarCtx = useContext(BottomTabBarContext)

  // const [routeName, setRouteName] = useState("LoungeList")

  useEffect(() => {
    setOptions({tabBarVisible: bottomTabBarCtx.isVisible})
  }, [bottomTabBarCtx.isVisible, setOptions])

  return <Stack.Navigator initialRouteName={"LoungeList"}>
    <Stack.Screen
      name="LoungeList"
      component={List}
      options={{headerShown: false}}
    />

    <Stack.Screen
      name="LoungeDetails"
      component={Details}
      options={{
        headerLeft : buttonProps => <BackButton {...buttonProps} />,
        headerRight: buttonProps => <LoungeHeaderRightDetailsButton {...buttonProps} />,
        headerTitle: 'Lounge Details',
      }}
    />

    <Stack.Screen
      name="LoungeParticipants"
      component={Participants}

      options={{
        headerLeft : buttonProps => <BackButton {...buttonProps} />,
        headerRight: buttonProps => <LoungeHeaderRightDetailsButton {...buttonProps} />,
        headerTitle: 'Lounge Participants',
      }}
    />

    <Stack.Screen
      name="LoungeAdd"
      component={LoungeEdit}

      options={{
        headerLeft : buttonProps => <BackButton {...buttonProps} />,
        headerTitle: 'Create Lounge',
      }}
    />

    <Stack.Screen
      name="LoungeEdit"
      component={LoungeEdit}

      options={{
        headerLeft : buttonProps => <BackButton {...buttonProps} />,
        headerTitle: 'Edit Lounge',
      }}
    />

...

上面的文件简单地定义了可以在应用程序的这一部分导航到的路由。

初始screen/route姓名='LoungeList'

一切正常。

LoungeList 屏幕上,我点击一个休息室摘要单元格(请发挥你的想象力),然后点击将我带到下面的屏幕:LoungeDetails

LoungeDetails 屏幕中,我看到了休息室的详细信息,在该屏幕上,还有一个 加入按钮。这个按钮可以让我加入休息室。

功能应该是,当用户点击加入按钮时,按钮进入加载状态,加载完成后,它应该显示为 Joined.这种情况应该发生但是发生后立即发生我被导航到 LoungeList 屏幕

下面是我为加入休息室而执行的代码:

const userDidJoinLounge = (joinedLounge: LoungeWithUsers) => {

    if(joinedLounge){

      console.log("joinedLounge before update == ", joinedLounge);
      
      const allLoungesNew = LoungeController.replaceLoungeInLoungeArray(
        userCtx.allLoungesList,
        joinedLounge
      );

      const userLoungesNew = LoungeController.getUserJoinedLoungeArrayListOnJoin(
        allLoungesNew,
        userCtx.userLoungeList,
        joinedLounge
      );

      console.log("allLounges after update == ", allLoungesNew);
      console.log("joinedLounges after update == ", userLoungesNew);

      userCtx.updateLoungeLists(allLoungesNew, userLoungesNew)

    }
  }

在上面的函数中,行

userCtx.updateLoungeLists(allLoungesNew, userLoungesNew) 接受两个参数,应用程序中所有休息室的列表,以及用户已加入的休息室列表。此函数更新保存这两个值的上下文。


大问题

问题我一直被重定向到 LoungeList 屏幕,即使没有任何代码指示应用程序这样做 .

可能有帮助的事情

我试过很多东西,有一些东西可以帮助你弄清楚发生了什么:

如何在用户点击加入按钮时阻止 react-navigation 离开屏幕?

非常感谢您的帮助。我希望我已经给了你足够的信息来解决这个问题。随时提出任何问题以帮助解决问题。我会告诉你我可以做什么。

在互联网上搜索了大约 3 天的答案后,答案非常简单。

我发现了很多文章和建议,告诉我不要在组件本身内放置任何用于创建 导航器的代码。

我并没有为这个应用程序编写原始代码,我是大约 2 个月前开始的,当我查看嵌套导航器时,并没有立即想到我认为问题可能在导航 chain/stack.

的上方

在根 index.tsx 文件中,以前的开发人员将根导航器(包含所有其他 sub/nested 导航器的导航器)放在入口点组件中。

此文件是在组件中创建任何导航器的唯一位置,但我不想去那里查看,因为该行为似乎局限于应用程序的休息室部分

解决方案

无论如何,修复很简单。在根 index.tsx 文件中,我将每个导航器声明移出了(根)功能组件,这解决了问题。

很明显,每当我对我的 UserContext 中保存的状态调用状态更改时,导航器都处于 unmourned/remounted,现在这很有意义,因为创建导航器的代码在组件内部,无论何时我会更改状态,导航器也会重新呈现,这让我回到 initialRouteName 屏幕。

主要经验教训

React Navigation v5 与其早期版本不同,现在允许我们使用 JSX 标签声明导航器,这通过为导航器的动态配置等提供机会,为我们提供了更大的灵活性,但是我们必须小心 其中 any/all 个导航器被声明

在解决这个问题 3 天后,一切都指向这个解决方案,但我不认为我正在处理的代码是这种情况,因为除了 一个文件, 所有其他导航器声明都在组件外部进行。

你可能也一样。 如果您在状态更改时出现这种行为,那么问题导航器可能就在您的导航器链中

我希望这对某人有所帮助!