在参数中传递函数时在导航状态中发现不可序列化的值

问题描述 投票:0回答:4

我有两个屏幕:

屏幕A

import React, { useState } from "react";
import { Text, View, Button } from "react-native";
const ViewA = ({ navigation }) => {
  const [val, setVal] = useState(null);
  const [val2, setVal2] = useState(null);
  const callBack = (value1,value2) => {
    setVal(value1);
    setVal2(value2);
  };
  const onNextPress = () => {
    navigation.navigate("Second Screen", { callBack: callBack });
  };
  return (
    <View>
      <Text>{val}{val2}</Text>
      <Button title="Next" onPress={onNextPress} />
    </View>
  );
};
export default ViewA;

屏幕B

import React from "react";
import { View, Button } from "react-native";

const ViewB = ({ route, navigation }) => {
  const onBackPress = () => {
    const { callBack } = route.params;
    callBack(5,6); // Your new value to set
    navigation.goBack();
  };

  return (
    <View>
      <Button title="back" onPress={onBackPress} />
    </View>
  );
};
export default ViewB;

当我进入屏幕 B 时,会出现警告:在导航状态中发现不可序列化的值。我该如何解决?

reactjs react-native react-navigation
4个回答
33
投票

根据文档 我收到警告“在导航状态中发现了不可序列化的值”

如果您在参数中传递不可序列化的值(例如类实例、函数等),则可能会发生这种情况。 React Navigation 在这种情况下会向您发出警告,因为这可能会破坏其他功能,例如状态持久性深度链接等。

...

如果您不使用状态持久性或深层链接到接受参数中的函数的屏幕,则警告不会影响您,您可以安全地忽略它。要忽略警告,您可以使用

LogBox.ignoreWarnings

import { LogBox } from 'react-native';

LogBox.ignoreLogs([
  'Non-serializable values were found in the navigation state',
]);

另一种方法是将状态移至路由参数中,而不是

ViewA
的本地状态(这意味着您可以在导航时设置它):

import React, {useState, useEffect} from 'react';
import { Text, View, Button } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';

const Stack = createStackNavigator();

const ViewA = ({ route, navigation }) => {
  const onNextPress = () => {
    navigation.navigate("ViewB", {
      previousScreen: route.name
    });
  };

  return (
    <View>
      <Text>ViewA</Text>
      <Text>Params: {JSON.stringify(route.params)}</Text>
      <Button title="Next" onPress={onNextPress} />
    </View>
  );
};

const ViewB = ({ route, navigation }) => {
  const onBackPress = () => {
    navigation.navigate(route.params.previousScreen, {
      val: 5,
      val2: 6,
    })
  };

  return (
    <View>
      <Text>ViewB</Text>
      <Text>Params: {JSON.stringify(route.params)}</Text>
      <Button title="back" onPress={onBackPress} />
    </View>
  );
};

export default function App() {
  return (
    <NavigationContainer>
      <Stack.Navigator mode="modal">
        <Stack.Screen name="ViewA" component={ViewA} />
        <Stack.Screen name="ViewB" component={ViewB} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

零食


0
投票

无论如何,如果您仍然需要从另一个屏幕运行该回调,您可以创建一个自定义类来订阅事件并存储回调,如下所示:

class SetNewPropsListener {
    constructor(){
        this.listeners = []

        this.subscribe = ({ id, cb }) => {
            this.listeners = [...this.listeners.filter((x)=> x.id !== id), { id, cb }]
        }

        this.unsubscribe = ({ id }) => {
            this.listeners = this.listeners.filter((x)=> x.id !== id)
        }

        this.propogate = (id, newProps) => {
            this.listeners.forEach((x)=> x.id === id && x.cb(newProps))
        }
    }
}

export const SetNewProps = new SetNewPropsListener()

然后,在您导航的第一个屏幕中,您可以使用唯一的 id 注册回调函数,如下所示:

import { SetNewProps } from '../utils/EventListeners'
const callbackToInvokeFromOtherScreen = (newParamsFromNextScreen)=>{
    // do whatever with new values
}
componentDidMount(){
  SetNewProps.subscribe({ id: 'your_unique_id', cb: callbackToInvokeFromOtherScreen })
}

然后在导航到的下一个屏幕中,您可以从 SetNewProps 类实例访问存储的回调,并使用自定义参数执行它,如下所示:

import { SetNewProps } from '../utils/EventListeners'
const propsToPassToCallback = {}
SetNewProps.propogate('your_unique_id', propsToPassToCallback)

通过正确的逻辑,这个订阅者类方法可以解决许多问题,例如调用对等组件方法(例如,当您滑动删除交互时,您不希望在滑动另一个 ListView 项目时保持任何其他 ListView 项目保持打开状态)


0
投票

顶部的答案是正确的,不幸的是现在在React navigation 6中已经过时了。现在的方法是像这样传递route.params:

//Screen A

const userValues = (value1,value2)


const onNextPress = () => {
    navigation.navigate("ViewB", { userValues(value1,value2): route.params.userValues});
  };

我们将整个对象连同路由一起传递给子级,本质上是让子级接收并传回。


0
投票

我已经找到了解决方案。

例如,我有一个屏幕,它有一个根参数:用户,

我导航到 B 屏幕并将 Route.key 传递到那里

navigation.navigate('B', {routeKey: route.key})

现在在 B,我可以使用以下代码更改用户:

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

navigation.dispatch({
  ...CommonActions.setParams({ user: 'Wojtek' }),
  source: route.params.routeKey,
});
© www.soinside.com 2019 - 2024. All rights reserved.