Skip to content
Advertisement

React Native – pass callback to another screen

I have a screen with form. Now in that form there’s a button that opens another screen where user selects the target option and upon selection they’re navigated back to the original form (stack navigator), the reasoning is that user can also create a new option there so they go to the same UI as they would if editing options separately (which they can).

My code below solution works, but I get following warning:

Non-serializable values were found in the navigation state. This can break usage such as persisting and restoring state. This might happen if you passed non-serializable values such as function, class instances etc. in params. If you need to use components with callbacks in your options, you can use ‘navigation.setOptions’ instead. See https://reactnavigation.org/docs/5.x/troubleshooting#i-get-the-warning-non-serializable-values-were-found-in-the-navigation-state for more details.

Now that link suggests to use setOptions however that is more for like adding a button to header, which is not the case, user selects the option in the target screen by clicking on the option.

Here are important parts of the code:

// MAIN FORM SCREEN
<Button title={"Some Title"} onPress={openSelectItem}></Button>

const openSelectFish = () => {
    return navigation.navigate("ItemList", { sendItemBack: true, onGoBack: onSelectItem });
};

const onSelectItem = (item: ItemDTO) => {
    setItem(item.name); // basic useState
};

// THE OPTIONS SCREEN
const onChooseItem = (item: ItemDTO) => {
    console.log(this);
    if ((typeof route !== "object") || (typeof route.params !== "object")) return;
    if (!route.params.sendItemBack ?? true) return;
    route.params.onGoBack(item);
    return navigation.goBack();
};
// onChooseItem is then used in onPress of each option

Is there a better way how to send callback to the other screen?

Advertisement

Answer

It is not recommended to pass a callback function via the route params. Judging from your code and your explanation you want to actually pass data back to the screen on goBack.

Instead of doing

route.params.onGoBack(item);
return navigation.goBack();

we could just pass item back to MainFormScreen in its route params on navigation.goBack() and set the state directly in MainFormScreen in a useEffect. This prevents us from having to pass a function in the route params. Instead, we set the state directly in the form.

OptionsScreen Instead of calling goBack, we can use navigate as usual and pass item back to the MainFormScreen

return navigation.navigate('MainFormScreen', { item: item })

MainFormScreen Here, we do not pass a function anymore but react on route param changes.

const openSelectFish = () => {
    return navigation.navigate("ItemList", { sendItemBack: true });
};

const params = useMemo(() => route.params || {}, [route.params])

const [item, setItem] = useState()

const onSelectItem = useCallback((item: ItemDTO) => {
    setItem(item.name); // basic useState
}, [setItem]);

useEffect(() => {
   onSelectItem(params.item)
}, [params, onSelectItem])
User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement