Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React Native Error : Non-serializable values were found in the navigation state. onPress(Function)

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>
  );
}

like image 414
Chi Avatar asked Oct 19 '25 05:10

Chi


2 Answers

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', ]);

like image 180
Felipe Avatar answered Oct 21 '25 19:10

Felipe


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.

like image 35
estani Avatar answered Oct 21 '25 19:10

estani