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

React Native传递useState setter函数遇序列化警告的解决方法

React Native 传递useState setter到其他页面的警告解决方法

问题场景

你在React Native里想通过navigation.navigate把多个useState的setter函数传给Profile页面,当前代码如下:

const [firstName, setfirstName] = useState('');
const [dob, setDOB] = useState('');
const [medicalConditions, setMedicalConditions] = useState('');
const [allergies, setAllergies] = useState('');
const [bloodtype, setBloodtype] = useState('');
const [height, setHeight] = useState('');
const [weight, setWeight] = useState('');

return (
  <KeyboardAvoidingView style={styles.container} behavior="padding">
    <View style={styles.buttonContainer}>
      <TouchableOpacity
        onPress={() => navigation.navigate('Profile', {
          setMedicalConditions: (a) => setMedicalConditions(a),
          setAllergies: (b) => setAllergies(b),
          setBloodtype: (c) => setBloodtype(c),
          setHeight: (d) => setHeight(d),
          setWeight: (e) => setWeight(e)
        })}
        style={[styles.button, styles.buttonOutline]}>
        <Text style={styles.buttonText}>Edit</Text>
      </TouchableOpacity>
    </View>
  </KeyboardAvoidingView>
)

代码能正常运行,但会收到以下警告:

Non-serializable values were found in the navigation state. Check:
Profile > params.setMedicalConditions (Function)
This can break usage such as persisting and restoring state. This might happen if you passed non-serializable values such as function, class instances etc. in params. If you need to use components with callbacks in your options, you can use 'navigation.setOptions' instead.

你试过用DeviceEventEmitter但该API已废弃,需要其他解决办法。

解决办法

方法1:用React Context共享状态和setter

把需要跨页面共享的状态和setter放到Context里,这样Profile页面可以直接从Context获取setter,不用通过导航参数传递,从根源解决序列化问题。

  1. 创建ProfileContext.js:
import { createContext, useContext, useState } from 'react';

const ProfileContext = createContext();

export function ProfileProvider({ children }) {
  const [firstName, setFirstName] = useState('');
  const [dob, setDOB] = useState('');
  const [medicalConditions, setMedicalConditions] = useState('');
  const [allergies, setAllergies] = useState('');
  const [bloodtype, setBloodtype] = useState('');
  const [height, setHeight] = useState('');
  const [weight, setWeight] = useState('');

  return (
    <ProfileContext.Provider value={{
      firstName, setFirstName,
      dob, setDOB,
      medicalConditions, setMedicalConditions,
      allergies, setAllergies,
      bloodtype, setBloodtype,
      height, setHeight,
      weight, setWeight
    }}>
      {children}
    </ProfileContext.Provider>
  );
}

export function useProfile() {
  return useContext(ProfileContext);
}
  1. 在根组件(比如App.js)包裹ProfileProvider:
import { ProfileProvider } from './ProfileContext';

export default function App() {
  return (
    <ProfileProvider>
      {/* 你的导航组件和其他页面 */}
    </ProfileProvider>
  );
}
  1. 原页面不用传参数,直接跳转:
<TouchableOpacity
  onPress={() => navigation.navigate('Profile')}
  style={[styles.button, styles.buttonOutline]}>
  <Text style={styles.buttonText}>Edit</Text>
</TouchableOpacity>
  1. Profile页面直接用useProfile获取setter:
import { useProfile } from './ProfileContext';

function Profile() {
  const { setMedicalConditions, setAllergies, setBloodtype, setHeight, setWeight } = useProfile();

  // 直接调用这些setter即可更新状态
  return (
    {/* 你的编辑界面 */}
  );
}

方法2:编辑完成后返回数据给父页面

不用传递setter,而是把当前的状态数据传给Profile页面,编辑完成后把新数据带回来,父页面再更新状态。

  1. 父页面跳转时传当前数据:
<TouchableOpacity
  onPress={() => navigation.navigate('Profile', {
    currentProfile: {
      medicalConditions,
      allergies,
      bloodtype,
      height,
      weight
    }
  })}
  style={[styles.button, styles.buttonOutline]}>
  <Text style={styles.buttonText}>Edit</Text>
</TouchableOpacity>
  1. Profile页面接收数据,编辑完成后返回:
import { useRoute, useNavigation } from '@react-navigation/native';

function Profile() {
  const route = useRoute();
  const navigation = useNavigation();
  const [medicalConditions, setMedicalConditions] = useState(route.params.currentProfile.medicalConditions);
  // 其他状态同理初始化

  const handleSave = () => {
    // 把编辑后的数据返回给父页面
    navigation.navigate('原来的页面名称', {
      updatedProfile: {
        medicalConditions,
        allergies,
        bloodtype,
        height,
        weight
      }
    });
  };

  return (
    {/* 编辑界面,最后加个保存按钮调用handleSave */}
  );
}
  1. 父页面监听返回的更新数据:
    用useFocusEffect监听页面重新聚焦时的参数变化:
import { useFocusEffect } from '@react-navigation/native';
import { useCallback } from 'react';

// 父页面里
useFocusEffect(
  useCallback(() => {
    const updatedProfile = route.params?.updatedProfile;
    if (updatedProfile) {
      setMedicalConditions(updatedProfile.medicalConditions);
      setAllergies(updatedProfile.allergies);
      setBloodtype(updatedProfile.bloodtype);
      setHeight(updatedProfile.height);
      setWeight(updatedProfile.weight);
      // 清空参数,避免重复触发
      navigation.setParams({ updatedProfile: undefined });
    }
  }, [route.params, navigation])
);

方法3:用轻量状态管理库(比如Zustand)

如果你的状态需要在更多组件里共享,用Zustand会比Context更简洁。

  1. 安装Zustand:
npm install zustand
# 或者 yarn add zustand
  1. 创建store:
import { create } from 'zustand';

export const useProfileStore = create((set) => ({
  firstName: '',
  dob: '',
  medicalConditions: '',
  allergies: '',
  bloodtype: '',
  height: '',
  weight: '',
  setMedicalConditions: (value) => set({ medicalConditions: value }),
  setAllergies: (value) => set({ allergies: value }),
  setBloodtype: (value) => set({ bloodtype: value }),
  setHeight: (value) => set({ height: value }),
  setWeight: (value) => set({ weight: value }),
}));
  1. 父页面直接用store的状态:
import { useProfileStore } from './profileStore';

function ParentPage() {
  const { medicalConditions, allergies } = useProfileStore();

  return (
    <KeyboardAvoidingView style={styles.container} behavior="padding">
      <View style={styles.buttonContainer}>
        <TouchableOpacity
          onPress={() => navigation.navigate('Profile')}
          style={[styles.button, styles.buttonOutline]}>
          <Text style={styles.buttonText}>Edit</Text>
        </TouchableOpacity>
      </View>
    </KeyboardAvoidingView>
  );
}
  1. Profile页面直接调用store的setter:
import { useProfileStore } from './profileStore';

function Profile() {
  const { setMedicalConditions, setAllergies } = useProfileStore();

  // 直接调用setter更新状态
  return (
    {/* 编辑界面 */}
  );
}

临时方案:屏蔽警告(不推荐)

如果只是想暂时去掉警告,不解决根本问题,可以在导航配置里自定义序列化器,但这样会破坏状态持久化的功能,不建议长期使用:

import { NavigationContainer } from '@react-navigation/native';

export default function App() {
  return (
    <NavigationContainer
      serializer={{
        serialize: (state) => JSON.stringify(state),
        deserialize: (str) => JSON.parse(str),
        warnNonSerializable: false,
      }}
    >
      {/* 你的导航结构 */}
    </NavigationContainer>
  );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 14:37:56