React Native跨栈屏幕传状态修改函数报非序列化值错误如何解决
问题原因
React Navigation 默认对所有路由参数做可序列化校验,用来支撑状态持久化、崩溃后页面恢复、开发工具状态快照等核心能力。函数属于不可序列化的值,直接把handleNewFavourite塞进路由参数传递,就会触发Non-serializable values were found in the navigation state报错。
另外你当前DetailsScreen的参数写法本身存在错误:React Navigation 传入屏幕组件的固定props为navigation和route,所有路由参数都挂载在route.params下,直接从组件props解构lesson、handleNewFavourite是拿不到传值的。
注意:不要通过在导航配置中关闭
serializableCheck的方式绕过校验,这种方式属于治标不治本,后续App状态恢复、深链接跳转时很容易出现参数丢失、页面崩溃的问题。
可行实现方案
方案1:抽离共享状态(最推荐,适合长期维护的项目)
收藏状态属于跨页面复用的全局业务状态,最合理的方式是把状态和对应的操作方法抽离到公共Context,或者使用Zustand、Redux这类轻量全局状态库管理,两个页面直接从公共状态中读取方法和数据,完全不需要通过路由传函数。
简单实现示例:
- 新建公共收藏上下文,包裹导航容器:
// FavouriteContext.jsx import { createContext, useContext, useState } from 'react'; const FavouriteContext = createContext(null); export function FavouriteProvider({ children }) { const [favouriteList, setFavouriteList] = useState([]); const handleNewFavourite = (lesson) => { setFavouriteList(prev => { const isFav = prev.some(item => item.id === lesson.id); return isFav ? prev.filter(item => item.id !== lesson.id) : [...prev, lesson]; }); }; return ( <FavouriteContext.Provider value={{ favouriteList, handleNewFavourite }}> {children} </FavouriteContext.Provider> ); } export const useFavourite = () => useContext(FavouriteContext);
- 在App根组件把导航组件包在Provider内:
// App.jsx import { NavigationContainer } from '@react-navigation/native'; import { FavouriteProvider } from './FavouriteContext'; import RootStack from './RootStack'; export default function App() { return ( <FavouriteProvider> <NavigationContainer> <RootStack /> </NavigationContainer> </FavouriteProvider> ) }
- 修改HomeScreen跳转逻辑,只传可序列化的课程数据:
// HomeScreen <FlatList data={checkCategory()} renderItem={({item}) => ( <TouchableOpacity onPress={() => navigation.navigate('Details', { item })} > <LessonCard lesson={item} /> </TouchableOpacity> )} />
- 修改DetailsScreen逻辑,直接从Context拿更新方法,从路由参数拿课程数据:
// DetailsScreen import { useFavourite } from './FavouriteContext'; const LessonDetails = ({ route }) => { const { item: lesson } = route.params; const { handleNewFavourite } = useFavourite(); const [favourite, setFavourite] = useState<boolean>(lesson.favourite); return ( <LessonDetailsContainer> <LessonDetailsInfoContainer> <LessonDetailsCategoryHead> <LessonDetailsCategory>{lesson.category}</LessonDetailsCategory> <TouchableOpacity onPress={() => { setFavourite(!favourite); handleNewFavourite(lesson); }}> <LessonDetailsFavouriteIcon> {favourite ? '❤️' : '🤍'} </LessonDetailsFavouriteIcon> </TouchableOpacity> </LessonDetailsCategoryHead> {/* 其余原有渲染逻辑保持不变 */} </LessonDetailsInfoContainer> </LessonDetailsContainer> ) } export default LessonDetails;
方案2:页面聚焦时同步状态(适合简单轻量场景)
如果不想引入额外的全局状态,可以在详情页完成收藏操作后先把状态持久化到本地存储,首页监听页面聚焦事件,每次进入页面时重新拉取/同步收藏列表状态即可,全程不需要传递函数。
实现示例:
- HomeScreen添加页面聚焦监听,每次进入页面时同步最新收藏状态:
// HomeScreen import { useFocusEffect } from '@react-navigation/native'; import { useCallback } from 'react'; // 组件内 useFocusEffect( useCallback(() => { // 这里执行你原来的checkCategory、更新favouriteList的逻辑即可 // 比如从本地存储、接口重新拉取最新的收藏列表,刷新FlatList数据 }, []) );
- 详情页操作时先持久化状态,不需要回传函数:
// DetailsScreen <TouchableOpacity onPress={() => { setFavourite(!favourite); // 把最新的收藏状态写入本地存储/缓存 persistFavouriteStatus(lesson, !favourite); }}> {/* 按钮内容 */} </TouchableOpacity>
内容的提问来源于stack exchange,提问作者jvegax
相关产品推荐
相关产品推荐

