【问题标题】:How to properly type navigation passed as props with React-Navigation with expo如何正确键入作为道具传递的导航与 React-Navigation with expo
【发布时间】:2022-01-06 11:47:14
【问题描述】:

如何正确键入作为道具传递给另一个组件的导航?根据文档

应用中的每个屏幕组件都会自动提供导航道具。

还有,

要对我们的屏幕进行类型检查,我们需要对屏幕接收到的导航道具和路线道具进行注释。

type Props = NativeStackScreenProps<RootStackParamList, 'Profile'>;

我有一个带路由器的导航组件:

const App: React.FC = () => {
  const [userMetrics, setUserMetrics] = useState<UserMetrics>(null);
  const Stack = createNativeStackNavigator<RootStackParamList>();
  return (
    <UserMetricsContext.Provider value={{ userMetrics, setUserMetrics }}>
      <NavigationContainer>
        <Stack.Navigator initialRouteName="Home">
          <Stack.Screen name="Home" component={Home} />
          <Stack.Screen name="Tests" component={Tests} />
        </Stack.Navigator>
      </NavigationContainer>
    </UserMetricsContext.Provider>
  );
};

在主屏幕中,我想接收导航道具以将其进一步传递到表单,该表单有一个按钮,该按钮将导航到测试组件并将表单数据作为参数传递:

interface Props {
  navigation: NativeStackScreenProps<RootStackParamList, "Home">;
}

export const Home: React.FC<Props> = ({ navigation }) => {
  const { setUserMetrics } =
    useContext<IUserMetricsContextType>(UserMetricsContext);
  return (
    <View style={styles.container}>
      <StatusBar style="auto" />
      <HealthCheckForm onSubmit={setUserMetrics} navigation={navigation} />
    </View>
  );
};

现在问题开始在表单组件中可见,因为打字稿假设一个级别太多,我已经像在父 Home 组件中那样输入了道具:

interface Props {
  onSubmit: React.Dispatch<React.SetStateAction<UserMetrics>>;
  navigation: NativeStackScreenProps<RootStackParamList, "Home">;
}

打字稿希望我像这样使用它:

  const submitHandler = (data: UserMetrics) => {
    onSubmit(data);
    navigation.navigation.navigate("Tests", { userMetrics: data });
    console.log(data);
  };

但是,这不起作用,正确的 - 工作和导航用法是

navigation.navigate("Tests", { userMetrics: data });

当我导航到 Tests 组件并传递参数时,我不知道如何在 Test 组件中接收它们。我试图像这样类比地这样做:

interface Props {
  navigation: NativeStackScreenProps<RootStackParamList, "Tests">;
}

export const Tests: React.FC<Props> = ({ navigation }) => {
  const { userMetrics } =
    useContext<IUserMetricsContextType>(UserMetricsContext);
  console.log({ params: navigation.route.params });
  return (
    <View>
      <DisplayList />
    </View>
  );
};

我收到另一个关于读取未定义属性的错误。 谢谢

【问题讨论】:

    标签: javascript reactjs typescript react-native react-navigation


    【解决方案1】:

    有嵌套导航器的解决方案(从这里开始:https://reactnavigation.org/docs/nesting-navigators/)。但是,在这种情况下,我建议不要让您的 HealthCheckForm 了解导航状态。只需传递一个标准的 onSubmit() 属性并处理 Home 组件中的所有导航。

    另外作为提示,请确保正确设置您的RootStackParamList,以便“测试”路线期待{userMetrics: YourDataType}。这是一个随机的设置示例。

    export type RootStackParamList = {
        myRouteName: undefined;
        tests: { userMetrics: MyDataType }; // TS now expects MyDataType on the props for tests route
        terminalAndMate: {
            departingTerminal: WSFTerminal;
            arrivingTerminal: WSFTerminal;
        };
    ...
    

    我还建议以这种方式输入屏幕道具,而不是作为界面。 NativeStackScreenProps 可以携带 rootStackParamList 中定义的参数:

    type TestsScreenProps = NativeStackScreenProps<RootStackParamList, "tests">;
    

    通过这两项更改,tests 屏幕应该有 props.route.params,其中将包含 MyDataType。

    试试:https://reactnavigation.org/docs/5.x/typescript/

    -关于七号评论的补充-

    查看 NativeStackScreenProps 的类型声明。

    export declare type NativeStackScreenProps<ParamList extends ParamListBase, RouteName extends keyof ParamList = string> = {
        navigation: NativeStackNavigationProp<ParamList, RouteName>;
        route: RouteProp<ParamList, RouteName>;
    };
    

    通过像您一样制作界面,您是说该组件的props 类型是

    { navigation: { navigation: NativeStackNavigation..etc , route: RouteProp }}
    

    您可以看到它是双重嵌套的,并且不是必需的,因为库提供的类型支持您需要的所有功能。

    提交时 你的 onSubmit 函数看起来像这样:

    //home.tsx
    const onSubmit = (data: YourDataType) => {
    props.navigation.navigate("tests", { userMetrics: data});
    }
    
    return (
    //...stuff
    <YourFormComponent onSubmit={onSubmit} />
    

    通过这种方式,您的所有导航都由 home 处理,这与测试处于同一“级别”,并且您的导航更加简洁。

    应该不需要任何 useEffect 调用。

    【讨论】:

    • 嗨@Tyles S 非常感谢,你能解释一下为什么这里的类型比界面更可取吗?在这种情况下,单击按钮时,我只会更新 App 组件中的状态,然后通过 Context Api 分发该状态,那么在 App 中的 useEffect 中,我将在哪里更改屏幕?这可以被认为是一种效果,不应该在点击处理程序中进行管理吗?再次感谢您的澄清。
    • 见我附加的答案。评论框不够用:)
    猜你喜欢
    • 2020-10-27
    • 2018-10-30
    • 1970-01-01
    • 2022-01-24
    • 1970-01-01
    • 1970-01-01
    • 2020-10-10
    • 2021-12-10
    • 2020-10-08
    相关资源
    最近更新 更多