Expo Router返回时如何保留页面状态?避免重渲染
Expo Router 返回页面状态丢失的解决办法
Expo Router 默认采用类似 Web 的路由行为:跳转新页面时会卸载上一页组件,所以调用 router.back() 返回时,上一页会重新渲染,状态自然丢失。下面是几种比 Redux 更简便的解决方案,没必要切换到 React Navigation:
1. 用 useFocusEffect 控制副作用执行时机
如果只是不想让 useEffect 里的逻辑重复执行,或者需要在页面聚焦时更新状态,直接用 Expo Router 内置的 useFocusEffect(它基于 React Navigation 的同名 API):
import { useFocusEffect } from '@react-navigation/native'; import React from 'react'; import { Link } from 'expo-router'; export default function ScreenA() { useFocusEffect( React.useCallback(() => { // 只有页面首次加载,或者从其他页面返回聚焦时才会执行 console.log('Screen A 已聚焦'); return () => { // 页面失焦时的清理逻辑(可选) }; }, []) ); return <Link href="/screen-b">去 Screen B</Link>; }
这个方法不用额外存状态,只是控制代码执行时机,适合简单场景。
2. 开启页面持久化布局
如果需要完整保留页面的所有状态(比如输入框内容、滚动位置),可以在根布局里配置持久化:
// app/_layout.js import { Stack } from 'expo-router'; export default function RootLayout() { return ( <Stack screenOptions={{ // 开启滚动位置持久化 persistScrollPosition: true, // 关闭页面失焦时的卸载逻辑,保留组件状态 unmountOnBlur: false, }}> <Stack.Screen name="screen-a" /> <Stack.Screen name="screen-b" /> </Stack> ); }
设置 unmountOnBlur: false 后,页面切换时不会卸载上一页组件,状态自然保留。注意不要给太多页面开这个,避免内存占用过高。
3. 轻量跨页面状态方案(替代 Redux)
如果需要跨页面共享少量状态,用 React Context 或者本地存储就够了,比 Redux 简单太多:
React Context 示例
先创建一个状态上下文:
// app/contexts/PageState.js import { createContext, useContext, useState } from 'react'; const PageStateContext = createContext(); export function PageStateProvider({ children }) { const [inputValue, setInputValue] = useState(''); return ( <PageStateContext.Provider value={{ inputValue, setInputValue }}> {children} </PageStateContext.Provider> ); } export function usePageState() { return useContext(PageStateContext); }
然后在根布局里包裹:
// app/_layout.js import { Stack } from 'expo-router'; import { PageStateProvider } from './contexts/PageState'; export default function RootLayout() { return ( <PageStateProvider> <Stack> <Stack.Screen name="screen-a" /> <Stack.Screen name="screen-b" /> </Stack> </PageStateProvider> ); }
最后在 ScreenA 里使用:
import { TextInput } from 'react-native'; import { Link } from 'expo-router'; import { usePageState } from '../contexts/PageState'; export default function ScreenA() { const { inputValue, setInputValue } = usePageState(); return ( <> <TextInput value={inputValue} onChangeText={setInputValue} placeholder="输入内容" /> <Link href="/screen-b">去 Screen B</Link> </> ); }
返回 ScreenA 时,输入框的内容就会保留。
内容的提问来源于stack exchange,提问作者Marcel Cohen
相关产品推荐
相关产品推荐

