I am trying to resolve the error Non-serializable values were found in the navigation state. Alert > params.action[0].onPress (Function)
of React Native navigation. I don't think the function is not passed to the param like the error points out, but it kept returning this same error every time I pressed the icon. I'd appreciate any suggestions or comments.
export default function Alert({ route, navigation }) {
const { colors } = useTheme();
const { t } = useTranslation();
const { title, message, action, option, type } = route?.params;
const success = type === "success";
useEffect(() => {
const backHandler = BackHandler.addEventListener(
"hardwareBackPress",
() => !option?.cancelable
);
return () => backHandler.remove();
}, [option?.cancelable]);
const renderButtonFirst = () => {
const firstTitle = action?.[0]?.text ?? t("close");
const onPressNo = action?.[0];
return (
<TouchableOpacity
onPress={() => {
onPressNo?.onPress();
if (option?.cancelable) navigation.goBack();
}}
>
<Text>
{firstTitle}
</Text>
</TouchableOpacity>
);
};
const renderButtonSecond = () => {
const secondTitle = action?.[1]?.text;
const onPressYes = action?.[1];
if (title && onPressYes) {
return (
<TouchableOpacity
onPress={() => {
onPressYes?.onPress();
if (option?.cancelable) navigation.goBack();
}}
>
<Text>
{secondTitle}
</Text>
</TouchableOpacity>
);
}
};
return (
<View>
<Icon name={success ? "check-circle" : "question-circle"} />
</View>
<View>
<Text>
{title}
</Text>
<Text>
{message}
</Text>
</View>
<View >
{renderButtonFirst()}
{renderButtonSecond()}
</View>
</View>
</View>
);
}
And this is the parent component just in case. But this error is from the Alert
component as it says.
const onOpen = (type, title, link) => {
Alert.alert({
title: title,
message: `${t("do_you_want_open")} ${title} ?`,
action: [
{
text: t("cancel"),
onPress: () => console.log("Cancel Pressed"),
style: "cancel",
},
{
text: t("done"),
onPress: () => {
switch (type) {
case "web":
Linking.openURL(link);
break;
case "phone":
Linking.openURL("tel://" + link);
break;
case "email":
Linking.openURL("mailto:" + link);
break;
case "address":
Linking.openURL(link);
break;
}
},
},
],
});
};
{product?.website.length > 0 && (
<TouchableOpacity
onPress={() => {
onOpen("web", t("Website"), product?.website);
}}
>
<View>
<Image
source={Images}
/>
</View>
</TouchableOpacity>
)}
UPDATE 4/1 This is the Navigation component just in case;
import AlertScreen from "@screens/Alert";
export default function Navigator() {
...
return (
<AppearanceProvider>
<NavigationContainer theme={theme}>
<RootStack.Screen
name="Alert"
component={AlertScreen}
gestureEnabled: false,
}}
/>
</RootStack.Navigator>
</NavigationContainer>
</AppearanceProvider>
);
}
From the react navigation docs
This can happen if you are passing non-serializable values such as class instances, functions etc. in params. React Navigation warns you in this case because this can break other functionality such state persistence, deep linking etc.
If you don't use state persistence or deep link to the screen which accepts functions in params, then the warning doesn't affect you and you can safely ignore it. To ignore the warning, you can use YellowBox.ignoreWarnings.
If you are using react-native version > 0.63, use:
import { LogBox } from 'react-native';
LogBox.ignoreLogs([ 'Non-serializable values were found in the navigation state', ]);
I also got bitten by this. You cannot pass non-simple objects to the navigation.
The problem is not "directly" in the code you posted but somewhere else. Either the go-back triggered the problem "once more" or there is somewhere a line like:
navigation.navigate('Alert', { action: {onPress: some_function }, /* rest */ }
In any case, the problem is that action comes from the parameters and is expected to have am onPress
function. You cannot serialize a function an thus cannot model it like that.
Solution: Put that logic into a service and the parameters into the route, something like:
export Service {
do(actionDescription: {type: string, payload: any}) {
if (actionDescription.type === 'log') console.log(actionDescription.payload); // you get the idea
}
}
// in Alert
const onPressNo = () => Service.do(action?.[0].action);
// somewhere:
navitation.navigate('Alert', {action: [{action: {type: 'log', payload: 'Cancel Pressed'} /* complete... */]
So, past only simple objects to the navigation route. Use a pseudo-Command pattern, where the command state is passed into the route and the trigger is centralized somewhere else.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With