You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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这类轻量全局状态库管理,两个页面直接从公共状态中读取方法和数据,完全不需要通过路由传函数。
简单实现示例:

  1. 新建公共收藏上下文,包裹导航容器:
// 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);
  1. 在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>
  )
}
  1. 修改HomeScreen跳转逻辑,只传可序列化的课程数据:
// HomeScreen
<FlatList
  data={checkCategory()}
  renderItem={({item}) => (
    <TouchableOpacity
      onPress={() => navigation.navigate('Details', { item })}
    >
      <LessonCard lesson={item} />
    </TouchableOpacity>
  )}
/>
  1. 修改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:页面聚焦时同步状态(适合简单轻量场景)

如果不想引入额外的全局状态,可以在详情页完成收藏操作后先把状态持久化到本地存储,首页监听页面聚焦事件,每次进入页面时重新拉取/同步收藏列表状态即可,全程不需要传递函数。
实现示例:

  1. HomeScreen添加页面聚焦监听,每次进入页面时同步最新收藏状态:
// HomeScreen
import { useFocusEffect } from '@react-navigation/native';
import { useCallback } from 'react';

// 组件内
useFocusEffect(
  useCallback(() => {
    // 这里执行你原来的checkCategory、更新favouriteList的逻辑即可
    // 比如从本地存储、接口重新拉取最新的收藏列表,刷新FlatList数据
  }, [])
);
  1. 详情页操作时先持久化状态,不需要回传函数:
// DetailsScreen
<TouchableOpacity
  onPress={() => {
    setFavourite(!favourite);
    // 把最新的收藏状态写入本地存储/缓存
    persistFavouriteStatus(lesson, !favourite);
  }}>
  {/* 按钮内容 */}
</TouchableOpacity>

内容的提问来源于stack exchange,提问作者jvegax

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 19:36:19