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 路由配置。我这样说是因为当我将 initialRouteName 更改为 LoungeDetails 时,休息室详细信息屏幕(加入按钮所在的位置)闪烁,但它保持在同一屏幕上。这也告诉我,在该函数的末尾,堆栈导航器回落到 initialRouteName 是什么。
奇怪的是,当我只设置 allLoungesNew
时,应用程序不会导航到 initialRouteName
,似乎这个问题只发生在我设置 userLoungesNew
时userContext 的状态。
如何在用户点击加入按钮时阻止 react-navigation 离开屏幕?
非常感谢您的帮助。我希望我已经给了你足够的信息来解决这个问题。随时提出任何问题以帮助解决问题。我会告诉你我可以做什么。
在互联网上搜索了大约 3 天的答案后,答案非常简单。
我发现了很多文章和建议,告诉我不要在组件本身内放置任何用于创建 导航器的代码。
我并没有为这个应用程序编写原始代码,我是大约 2 个月前开始的,当我查看嵌套导航器时,并没有立即想到我认为问题可能在导航 chain/stack.
的上方
在根 index.tsx
文件中,以前的开发人员将根导航器(包含所有其他 sub/nested 导航器的导航器)放在入口点组件中。
此文件是在组件中创建任何导航器的唯一位置,但我不想去那里查看,因为该行为似乎局限于应用程序的休息室部分
解决方案
无论如何,修复很简单。在根 index.tsx
文件中,我将每个导航器声明移出了(根)功能组件,这解决了问题。
很明显,每当我对我的 UserContext 中保存的状态调用状态更改时,导航器都处于 unmourned/remounted,现在这很有意义,因为创建导航器的代码在组件内部,无论何时我会更改状态,导航器也会重新呈现,这让我回到 initialRouteName
屏幕。
主要经验教训
React Navigation v5 与其早期版本不同,现在允许我们使用 JSX 标签声明导航器,这通过为导航器的动态配置等提供机会,为我们提供了更大的灵活性,但是我们必须小心 其中 any/all 个导航器被声明
在解决这个问题 3 天后,一切都指向这个解决方案,但我不认为我正在处理的代码是这种情况,因为除了 一个文件, 所有其他导航器声明都在组件外部进行。
你可能也一样。 如果您在状态更改时出现这种行为,那么问题导航器可能就在您的导航器链中。
我希望这对某人有所帮助!
在此先感谢您帮助解决这个问题。
一些上下文(无双关语意)
我正在做一个公司的项目,这将限制我将所有代码放在这里,但我会尝试在不泄露国家机密的情况下尽可能多地放相关代码。
基本上,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 路由配置。我这样说是因为当我将 initialRouteName 更改为 LoungeDetails 时,休息室详细信息屏幕(加入按钮所在的位置)闪烁,但它保持在同一屏幕上。这也告诉我,在该函数的末尾,堆栈导航器回落到 initialRouteName 是什么。
奇怪的是,当我只设置
allLoungesNew
时,应用程序不会导航到initialRouteName
,似乎这个问题只发生在我设置userLoungesNew
时userContext 的状态。
如何在用户点击加入按钮时阻止 react-navigation 离开屏幕?
非常感谢您的帮助。我希望我已经给了你足够的信息来解决这个问题。随时提出任何问题以帮助解决问题。我会告诉你我可以做什么。
在互联网上搜索了大约 3 天的答案后,答案非常简单。
我发现了很多文章和建议,告诉我不要在组件本身内放置任何用于创建 导航器的代码。
我并没有为这个应用程序编写原始代码,我是大约 2 个月前开始的,当我查看嵌套导航器时,并没有立即想到我认为问题可能在导航 chain/stack.
的上方在根 index.tsx
文件中,以前的开发人员将根导航器(包含所有其他 sub/nested 导航器的导航器)放在入口点组件中。
此文件是在组件中创建任何导航器的唯一位置,但我不想去那里查看,因为该行为似乎局限于应用程序的休息室部分
解决方案
无论如何,修复很简单。在根 index.tsx
文件中,我将每个导航器声明移出了(根)功能组件,这解决了问题。
很明显,每当我对我的 UserContext 中保存的状态调用状态更改时,导航器都处于 unmourned/remounted,现在这很有意义,因为创建导航器的代码在组件内部,无论何时我会更改状态,导航器也会重新呈现,这让我回到 initialRouteName
屏幕。
主要经验教训
React Navigation v5 与其早期版本不同,现在允许我们使用 JSX 标签声明导航器,这通过为导航器的动态配置等提供机会,为我们提供了更大的灵活性,但是我们必须小心 其中 any/all 个导航器被声明
在解决这个问题 3 天后,一切都指向这个解决方案,但我不认为我正在处理的代码是这种情况,因为除了 一个文件, 所有其他导航器声明都在组件外部进行。
你可能也一样。 如果您在状态更改时出现这种行为,那么问题导航器可能就在您的导航器链中。
我希望这对某人有所帮助!