4

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

6
  • > I don't think the function is not passed to the param like the error points out: Can you post the full code of the Alert screen? And the code that navigates to Alert screen Commented Mar 11, 2022 at 11:24
  • I added the entire Alert component and the parent component. Could you take a look? Commented Mar 11, 2022 at 19:06
  • I don't see where you're navigating to the alert screen, but from the code you posted, I see you're passing functions in the action property of your params. Commented Mar 11, 2022 at 23:56
  • In the last column, there is onPress => onOpen which calls onOpen. Inside of the onOpen, there is <Alert> component. You are talking about the onPress: () => console.log("Cancel Pressed"), in the action? I deleted but still returning the error. Commented Mar 12, 2022 at 0:57
  • Your onOpen function calls Alert.alert, not navigating to a screen. I have no idea what Alert.alert does, is it using React Native's Alert? How does that result in navigation to the Alert screen? Regarding params, I'm talking about your Alert component. You're clearly reading action from params and calling functions on that (const onPressNo = action?.[0] onPressNo?.onPress()). Commented Mar 12, 2022 at 2:20

2 Answers 2

5

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

Sign up to request clarification or add additional context in comments.

2 Comments

I want to solve this error, and ignoring is not the solution.
Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
1

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.