gpt4 book ai didi

javascript - React Navigation 5 - 在导航到另一个选项卡中的另一个堆栈之前重置堆栈(类似于 popToTop())

转载 作者:行者123 更新时间:2023-12-03 06:55:20 25 4
gpt4 key购买 nike

假设 Tab Navigator 中有两个堆栈屏幕:

  1. Tab A -> Camera
  2. Tab B -> Profile

在配置文件屏幕中,在其堆栈中推送了相同类型的其他屏幕(“配置文件”)(具有不同的参数)。现在,如果您在“相机”屏幕中并执行以下操作:
    navigation.navigate("Profile", { screen: "Profile", params });
您将导航到“配置文件”屏幕,这些参数将被发送到堆栈中的最后一个屏幕。如果我想导航到传递参数的堆栈的根,我该怎么办?
我尝试过:
   // In the profile screen
useEffect(() => {
if (navigation.canGoBack())
navigation.popToTop(); // Go back to the root of the stack

showParams(params);
}, [params])
但是有了这个,“showParams”操作不会在根目录中执行,我也不会从“相机”屏幕直接导航到堆栈的根目录。
我想在导航之前我必须在相机屏幕上做这样的事情:
  navigation.dispatch(
CommonActions.reset({
// some stuff
})
);

navigation.navigate("Profile", { screen: "Profile", params });
但是我找不到任何方法来实现我的目标。
有任何想法吗?谢谢你。
更新 - 我的导航系统
堆栈(这里我定义了多个堆栈:“HomeStacks”、“SearchStacks”、“ProfileStacks”......)
const Stack = createStackNavigator();

export function ProfileStacks() { <------ Over this stack I do .push()
return (
<Stack.Navigator
initialRouteName="Profile"
>
<Stack.Screen name="Profile" children={Profile} />
<Stack.Screen name="EditProfile" children={EditProfile} />
</Stack.Navigator>
);
}

...
底部标签导航器
<Tab.Navigator>
<Tab.Screen
name="Camera"
component={CameraPlaceholder}
listeners={({ navigation }) => ({
tabPress: (event) => {
event.preventDefault();
navigation.navigate("CameraModal");
},
})}
/>

<Tab.Screen
name="Profile"
component={ProfileStacks}
/>
</Tab.Navigator>
ROOT STACK NAVIGATOR(应用程序的主要导航器)
在这个堆栈中,我实现了身份验证流程,并且我声明了一些额外的堆栈(仅用于外观目的)。
export default function RootNavigator(props) {
/*
This navigator is implemented using the
'Protected Routes' pattern
*/
const { isUserLoggedIn } = props;

const RootStack = createStackNavigator();

return (
<RootStack.Navigator>
{isUserLoggedIn ? (
<>
<RootStack.Screen
name="BottomTabNavigator"
component={BottomTabNavigator}
/>

<RootStack.Screen
name="CameraModal"
component={Camera}
/>
</>
) : (
<>
<RootStack.Screen name="SignIn" component={SignIn} />

<RootStack.Screen
name="SignUp"
component={SignUp}
/>

<RootStack.Screen
name="ForgotPassword"
component={ForgotPassword}
/>
</>
)}
</RootStack.Navigator>
);
我见过的相关问题
How to reset a Stack in a different Tab using React Navigation 5.x
https://github.com/react-navigation/react-navigation/issues/6639
https://github.com/react-navigation/react-navigation/issues/8988
这是我的个人资料选项卡的导航数据
  Object {
"key": "Profile-Ty4St1skrxoven-jkZUsx",
"name": "Profile",
"params": undefined,
"state": Object {
"index": 1,
"key": "stack-8nWDnwDJZRK8iDuJok7Hj",
"routeNames": Array [
"Profile",
"EditProfile",
],
"routes": Array [
Object {
"key": "Profile-m0GQkvNk5RjAhGABvOy9n",
"name": "Profile",
"params": undefined,
},
Object {
"key": "Profile-tZAEmSU0eEo1Nt7XC09t1",
"name": "Profile",
"params": Object {
"otherUserData": Object {
"username": "jeffbezos",
},
"post": null,
},
},
],
"stale": false,
"type": "stack",
},
},
],
"stale": false,
"type": "tab",
},
我只需要从我的应用程序的另一个选项卡的选项卡“配置文件”中的堆栈“配置文件”中弹出第二条路由,然后导航到此屏幕。

最佳答案

更新(重构代码)

import { useNavigation, CommonActions } from "@react-navigation/native";

export default function useResetProfileStackNavigator() {
const navigation = useNavigation();

return () => {
const bottomTabNavigator = navigation
.getState()
?.routes?.find(({ name }) => name === "BottomTabNavigator");

const profileTab = bottomTabNavigator?.state?.routes?.find(
({ name }) => name === "ProfileStacks"
);

const { key: target, routes } = profileTab?.state ?? {};

if (!target || routes?.length <= 1) return;

routes.length = 1; // popToTop()

navigation.dispatch({
...CommonActions.reset({ routes }),
target,
});
};
}
以下是如何使用它:
export default function useSendPostToProfile() {
const navigation = useNavigation();

const isSending = useRef(false);

const resetProfileStackNavigator = useResetProfileStackNavigator();

return (post) => {
if (isSending.current) return;

isSending.current = true;

// Make sure there is only one route open in the profile stack
resetProfileStackNavigator();

navigation.navigate("BottomTabNavigator", {
screen: "ProfileStacks",
params: {
screen: "Profile",
params: {
post,
},
},
});
};
}

以前的解决方案
经过几个小时的研究,我找到了解决方案。这不是最好的,但它适用于我的用例,它肯定适用于其他人的用例。
我试图实现的是重置堆栈导航器中的“配置文件”屏幕的路线,而堆栈导航器又位于我当前堆栈屏幕所在的选项卡导航器的另一个选项卡中。这听起来有点令人困惑,但它基本上类似于上传照片时在 Instagram 上发生的情况。
如果在 Instagram 中,您从主屏幕导航到其他用户个人资料,然后将照片上传到您的帐户,您将看到如何从“发布您的照片”屏幕转到“主页”选项卡中堆栈导航器的根目录,饲料。
在我的用例中,我正在做类似的事情,我可以从我自己的个人资料导航到其他用户的个人资料,并且照片会上传到此屏幕中,并带有进度条。
从一开始我就想到使用navigation.popToTop(),但我一直无法获得我想要的结果,因为正如我之前在问题中评论的那样,参数(包含帖子的)丢失了。所以我别无选择,只能从我的“发布照片”屏幕中模拟这种行为。
我遵循的步骤如下:
  1. As my "publish photo" screen shares the navigation with my "profile" screen, through the tab navigator (which is obvious, since if it were not like that I could not do the navigation.navigate()), I have followed the navigation path from this to the Stack Navigator of the Profile Tab and then I have tried to take both its key and its routes.

  1. In case I have found the current key and paths, that means the stack navigator is mounted (in my case, the tab does a lazy initialization of all my pages, that's why I speak of "trying to take"). So it will be necessary to apply steps 3 and 4.

  1. Simulate the navigation.popToTop() reducing the size of the routes to 1 (note that the root of the stack navigator is the item in the first position of the "routes" array)

  1. Dispatch the reset operation over the profile's stack navigator using the navigation API.

  1. The final step, navigate to the stack screen normally passing the photo as param.

这是代码:
  const resetProfileStackNavigator = () => {
const currentNavigationState = navigation.dangerouslyGetState();

// Find the bottom navigator
for (let i = 0; i < currentNavigationState?.routes?.length; i++) {
if (currentNavigationState.routes[i].name === "BottomTabNavigator") {
// Get its state
const bottomNavigationState = currentNavigationState.routes[i].state;

// Find the profile tab
for (let j = 0; j < bottomNavigationState?.routes?.length; j++) {
if (bottomNavigationState.routes[j].name === "Profile") {
// Get its state
const profileTabState = bottomNavigationState.routes[j].state;

// Get the key of the profile tab's stack navigator
var targetKey = profileTabState?.key;
var targetCurrentRoutes = profileTabState?.routes;

break;
}
}
break;
}
}

// Reset the profile tab's stack navigator if it exists and has more than one stacked screen
if (targetKey && targetCurrentRoutes?.length > 1) {
// Set a new size for its current routes array, which is faster than Array.splice to mutate
targetCurrentRoutes.length = 1; // This simulates the navigation.popToTop()

navigation.dispatch({
...CommonActions.reset({
routes: targetCurrentRoutes, // It is necessary to copy the existing root route, with the same key, to avoid the component unmounting
}),
target: targetKey,
});
}
}


/*
Maybe, the stack navigator of the profile tab exists and has changed from its initial state...
In this situation, we will have to find the key of this stack navigator, which is also
nested in the same tab navigator in which this stack screen is.
*/
resetProfileStackNavigator();

// Finally, navigate to the profile stack screen and pass the post as param
navigation.navigate("Profile", {
screen: "Profile",
params: {
post,
},
});
Pd:我知道有一些适用的重构,但我更喜欢以这种方式显示代码,以便我上面讨论的步骤清晰可见。
如果有读过这篇文章的人设法 将这段代码概括为
使用 ES6 的通用函数
,请留下它作为答案,因为它对我和其他用户都非常有用。

关于javascript - React Navigation 5 - 在导航到另一个选项卡中的另一个堆栈之前重置堆栈(类似于 popToTop()),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64515420/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com