Expo与React Native中实现多次跳转同一路由并保留返回历史的导航问题
我完全理解你现在的困扰——你想要在不同的Profile页面之间跳转时,每一次跳转都能在导航栈里留下记录,这样点击左上角的返回按钮就能按浏览顺序回到之前的Profile,而不是直接跳回Feed页面。但目前不管用<Link>组件还是router.push都没达到预期效果,这其实是Expo Router的默认路由复用行为导致的,下面我给你两种可行的解决方案:
问题原因分析
Expo Router默认会对**相同路由路径(即使URL参数不同)**的页面进行组件复用,不会在导航栈中新增条目。比如你从Profile 1跳到Profile 2再跳回Profile 1时,导航栈里其实只有「Feed → 最后一次的Profile 1」这两个条目,所以点击返回会直接回到Feed,而不是之前的Profile 2。
方法一:使用React Navigation原生push方法(推荐)
Expo Router底层基于React Navigation,我们可以直接使用它的navigation.push方法,这个方法会强制在导航栈中添加新条目,即使路由路径相同但参数不同。
步骤:
- 首先在Profile页面导入
useNavigation钩子:
import { useNavigation } from '@react-navigation/native';
- 获取导航对象,替换原来的
router.push为navigation.push:
import { View, Text, Button } from 'react-native'; import { Stack, useSearchParams } from 'expo-router'; import { StatusBar } from 'expo-status-bar'; import { useNavigation } from '@react-navigation/native'; const ProfilPage = () => { const navigation = useNavigation(); const { id } = useSearchParams(); return ( <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> <Stack.Screen options={{ headerTitle: `Details #${id}` }} /> <Text>Profil for : {id}</Text> <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center', gap: 100 }}> {/* 使用navigation.push,第一个参数是路由名称(对应文件路径),第二个是参数 */} <Button title="Profil One" onPress={() => navigation.push('feed/profil/[id]', { id: '1' })} /> <Button title="Profil Two" onPress={() => navigation.push('feed/profil/[id]', { id: '2' })} /> <Button title="Profil Three" onPress={() => navigation.push('feed/profil/[id]', { id: '3' })} /> </View> <StatusBar style="light" /> </View> ); }; export default ProfilPage;
这样修改后,每次跳转Profile页面都会在导航栈里新增一个条目,点击返回按钮就会按顺序回到上一个Profile页面,最后才回到Feed。
方法二:添加唯一查询参数(快速生效的hack方式)
如果你不想引入React Navigation的原生API,可以给每次跳转的URL添加一个唯一的查询参数(比如时间戳),让Expo Router认为这是不同的路由,从而创建新的栈条目。
修改后的Profile页面代码:
import { View, Text, Button } from 'react-native'; import { Stack, useSearchParams } from 'expo-router'; import { StatusBar } from 'expo-status-bar'; import { useRouter } from 'expo-router'; const ProfilPage = () => { const router = useRouter(); const { id } = useSearchParams(); // 封装跳转方法,添加唯一时间戳参数 const navigateToProfile = (profileId: string) => { router.push(`/feed/profil/${profileId}?t=${Date.now()}`); }; return ( <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> <Stack.Screen options={{ headerTitle: `Details #${id}` }} /> <Text>Profil for : {id}</Text> <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center', gap: 100 }}> <Button title="Profil One" onPress={() => navigateToProfile('1')} /> <Button title="Profil Two" onPress={() => navigateToProfile('2')} /> <Button title="Profil Three" onPress={() => navigateToProfile('3')} /> </View> <StatusBar style="light" /> </View> ); }; export default ProfilPage;
这种方法的原理是让每次跳转的URL都是唯一的,Expo Router会将其视为不同的路由,从而在栈中添加新条目。缺点是URL会带有额外的参数,但胜在实现简单,不需要依赖额外的API。
备注:内容来源于stack exchange,提问作者Jérémie Chazelle

