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

Ini*_*ebi 4 reactjs react-native react-navigation react-context react-navigation-v5

提前感谢您帮助解决这个问题。


一些上下文(无双关语)

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

基本上,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',
      }}
    />

...
Run Code Online (Sandbox Code Playgroud)

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

初始屏幕/路线名称 = 'LoungeList'

这一切正常。

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

LoungeDetails屏幕内,我看到了Lounge的详细信息,在该屏幕上,还有一个加入按钮。此按钮使我能够加入休息室。

功能应该是,当用户点击加入按钮时,按钮进入加载状态,当它完成加载时,它应该显示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)

    }
  }
Run Code Online (Sandbox Code Playgroud)

在上面的函数中,行

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


大问题

问题我一直被重定向到 LoungeList 屏幕,即使没有任何代码指示应用程序执行此操作

可能有帮助的事情

我玩过很多东西,一些可以帮助你弄清楚发生了什么的事情是:

  • 似乎正在重新渲染 React Navigation 路由配置。我这样说是因为当我将 initialRouteName 更改为LoungeDetails 时,休息室详细信息屏幕(加入按钮所在的位置)闪烁,但它保持在同一屏幕上。这也告诉我,在该函数结束时,堆栈导航器回退到任何initialRouteName是什么。

  • 奇怪的是,当我只设置allLoungesNew然后应用程序不会导航到 时initialRouteName,似乎这个问题只发生在我设置userLoungesNewuserContext 的状态时。

当用户点击加入按钮时,如何阻止反应导航离开屏幕?

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

Ini*_*ebi 5

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

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

我没有为这个应用程序编写原始代码,我是在大约 2 个月前加入的,虽然我查看了嵌套的导航器,但我并没有立即意识到问题可能在导航链/堆栈的更高层。

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

这个文件是在组件中创建任何导航器的唯一地方,但我没想到那里看,因为行为似乎本地化到应用程序的休息室部分

解决方案

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

很明显,每当我在我的 UserContext 中调用状态更改时,导航器都会被取消/重新安装,现在这是有道理的,因为创建导航器的代码在组件内部,每当我更改状态时,导航器也会被重新渲染,这让我回到了initialRouteName屏幕。

主要经验教训

React Navigation v5 与其早期版本不同,现在允许我们使用 JSX 标签声明导航器,这为我们提供了更多的灵活性,例如我们的导航器的动态配置,但是我们必须小心任何/所有导航器的位置宣布

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

对你来说可能是一样的。如果您在状态更改时遇到这种行为,那么问题 navigator 可能在您的 navigators 链上

我希望这可以帮助别人!