如何在 React Navigation 5 中将父函数传递给子屏幕?

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

最近我开始使用 React Native 0.61.5 和 React 导航 5.x。现在我需要将父函数传递给子屏幕。例如,我想通过按下嵌套在 StackNavigator 中的 TabNavigator 选项卡中的按钮来更改导航栏图标。以前(导航版本 3.x)我使用 getActiveChildNavigationOptions 来满足我的需要,但现在它被删除了。所以实现这个目标的唯一方法就是将自定义函数传递给子组件。

在示例代码中,我想将 XXXXXXXX 更改为 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>
)

一切正常,但我收到此警告:

全文:

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.

如果警告说我不能使用路由参数传递函数,我该如何将函数从父子传递给子?

警告中 link 指向的文档页面说:

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.

所以,在我的例子中,我可以忽略这个警告并通过路由参数安全地传递函数。

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

或者对于 React Native 0.63 及更高版本:

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

YellowBox 在 react-native > 0.6 中被弃用。使用以下代码并记住这不是主要错误。这只是一个警告

import { LogBox } from 'react-native';
LogBox.ignoreLogs([
  'Non-serializable values were found in the navigation state',
]);

哦。知道它不见了。谢谢

注意:并且上面的问题是通过initialParams将setState常量变量传递给屏幕的。所以我们不能通过 initialParams 传递函数或任何其他可执行模块,这只能传递字符串类型的数据。所以请使用以下代码传递函数、设置变量等...

const [HeaderRightName,setHeaderRightName] = React.useState('');
<Tabs.Screen name="tab-a" options={{ headerShown: false }} >
           {(props) => (
                <TabA setHeaderRightName={setHeaderRightName} {...props}/>
           )}
</Tabs.Screen
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>
    );
  }
}