Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass parent function to child screen in React Navigation 5?

Recently I have started using React Native 0.61.5 and React navigation 5.x. Now I need to pass a parent function into a child screen. For example, I want to change navbar icon by pressing button in tab of TabNavigator nested in StackNavigator. Previously (navigation ver. 3.x) I was using getActiveChildNavigationOptions for my needs but now it's removed. So the only way to achieve this goal is to pass custom functions to child components.

Here in example code I want to change from XXXXXXXX to YYYYYYYYY:

const TabA = ({ route }) => (
  <View>
    <Text>Tab A</Text>
      <Button 
        title="Change header"
        onPress={() => route.params.setHeaderRightName("YYYYYYYYY")}/>
  </View>
)

const TabB = () => <><Text>Tab B</Text></>

const Tabs = createBottomTabNavigator();
const TabsNavigator = ({ navigation }) => {
  const [headerRightName, setHeaderRightName] = useState("XXXXXXXX");

  useLayoutEffect(() => navigation.setOptions({
    headerRight: () => <MyNavIcon name={headerRightName}/>
  }), [headerRightName]);

  return (
    <Tabs.Navigator>
      <Tabs.Screen name="tab-a" component={TabA} initialParams={{ setHeaderRightName }} />
      <Tabs.Screen name="tab-b" component={TabB} />
    </Tabs.Navigator>
  );
}

const Stack = createStackNavigator();
export default App = () => (
  <NavigationContainer>
    <Stack.Navigator>
      <Stack.Screen name="tabs" component={TabsNavigator} />
      <Stack.Screen name="another-screen" component={AnotherScreen} />
    </Stack.Navigator>
  </NavigationContainer>
)

Everything is working fine, but I am getting this warning:

enter image description here

Full text:

Non-serializable values were found in the navigation state, which 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/troubleshooting#i-get-the-warning-non-serializable-values-were-found-in-the-navigation-state for more details.

So how can I pass function from parent to child if warning says I cannot pass function using route params?

like image 606
matusalem Avatar asked Mar 31 '20 15:03

matusalem


2 Answers

class MainScreen extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      title: null
    };

    this.updateTitle = this.updateTitle.bind(this);
  }

  updateTitle(title) {
    this.setState({title: title});
  }

  render() {
    return (
      <NavigationContainer>
        <Stack.Navigator>
          <Stack.Screen 
          name="NewScreen"
          options={{
            headerShown: true,
            headerTitle: this.state.title
          }}>
            {(props) => <NewScreen  {...props} updateTitle={this.updateTitle}/>}
          </Stack.Screen>
        </Stack.Navigator>
      </NavigationContainer>
    );
  }
}
like image 60
Churaev Andrey Avatar answered Sep 28 '22 00:09

Churaev Andrey


The documentation page the link in the warning is pointing to says:

If you don't use state persistence or deep link to the screen which accepts functions in params, then you can ignore the warning. To ignore it, you can use YellowBox.ignoreWarnings.

So, in my case, I can ignore this warning and pass functions thought route params safely.

YellowBox.ignoreWarnings([
  'Non-serializable values were found in the navigation state',
]);

or for react native 0.63 and higher:

LogBox.ignoreLogs([
  'Non-serializable values were found in the navigation state',
]);
like image 27
matusalem Avatar answered Sep 28 '22 01:09

matusalem