我有两个屏幕:
屏幕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 时,会出现警告:在导航状态中发现不可序列化的值。我该如何解决?
如果您在参数中传递不可序列化的值(例如类实例、函数等),则可能会发生这种情况。 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>
);
}
无论如何,如果您仍然需要从另一个屏幕运行该回调,您可以创建一个自定义类来订阅事件并存储回调,如下所示:
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 项目保持打开状态)
顶部的答案是正确的,不幸的是现在在React navigation 6中已经过时了。现在的方法是像这样传递route.params:
//Screen A
const userValues = (value1,value2)
const onNextPress = () => {
navigation.navigate("ViewB", { userValues(value1,value2): route.params.userValues});
};
我们将整个对象连同路由一起传递给子级,本质上是让子级接收并传回。
我已经找到了解决方案。
例如,我有一个屏幕,它有一个根参数:用户,
我导航到 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,
});