为反应导航道具添加强类型

问题描述 投票:0回答:14

我在我的react-native项目(expo)中使用typescript。

该项目使用反应导航,所以在我的屏幕上我可以设置

navigationOptions
并且我可以访问道具
navigation

现在我尝试对这些进行强类型化,以便获得可设置哪些属性的提示。

interface NavStateParams {
    someValue: string
}

interface Props extends NavigationScreenProps<NavStateParams> {
   color: string
}

class Screen extends React.Component<Props, any> {
    // This works fine
    static navigationOptions: NavigationStackScreenOptions = {
        title: 'ScreenTitle'
    }
    // Does not work
    static navigationOptions: NavigationStackScreenOptions = ({navigation, screenProps }) => ({
        title: navigation.state.params.someValue
    })
}

将反应导航作为组件的道具处理的最佳方法是什么。

typescript react-native react-navigation
14个回答
48
投票

只需将 NavigationType 添加到您的 Props 中,如下所示:

    import { StackNavigator, NavigationScreenProp } from 'react-navigation';

    export interface HomeScreenProps {
      navigation: NavigationScreenProp<any,any>
    };

    export class HomeScreen extends React.Component<HomeScreenProps, object> {

      render() {
        return (
          <View style={styles.container}>       
            <Button
              title="Go to Details"
              onPress={() => this.props.navigation.navigate('Details')}
            />
          </View>
        );
      }
    }

40
投票

如果您传递由

 定义的 
navigation

属性
let navigation = useNavigation()

对于组件,最好的输入方式是:

import {NavigationProp, ParamListBase} from '@react-navigation/native';

navigation: NavigationProp<ParamListBase>

更新:

这是一种更好的强导航输入方法,使用最新的

@react-navigation
版本 (
6.x
)

完整示例:

import {NativeStackNavigationProp} from '@react-navigation/native-stack';

type RootStackParamList = {

   ScreenOne: undefined; //current screen

   ScreenTwo: {slug: string}; // a screen that we are 
// navigating to, in the current screen,
// that we should pass a prop named `slug` to it

   ScreenThree: {data: Array<string>};

   ScreenFour: undefined; // a screen that we are navigating to 
// in the current screen, that we don't pass any props to it
};

interface IPageProps {
   navigation: NativeStackNavigationProp<RootStackParamList, 'ScreenOne'>;
}

// Since our screen is in the stack, we don't need to 
// use `useNavigation()` to provide the `navigation` to
// our component, we just need to read it as a prop

function Pdp({navigation}: IPageProps) {
   return ...
}

14
投票

最低配置,版本 6.x

import { NavigationProp } from "@react-navigation/native";

interface RouterProps {
    navigation: NavigationProp<any, any>;
}

<TouchableOpacity onPress={() => navigation.navigate('Home')}>
    <Text>Navigate to Home</Text>
</TouchableOpacity>

5
投票

这有效:

static navigationOptions = ({ navigation }: NavigationScreenProps) => ({
  ...
})

4
投票

我有同样的问题,这是我的解决方案:

import * as React from 'react'
import { NavigationScreenProps, NavigationStackScreenOptions } from 'react-navigation'

interface NavStateParams {
  someValue: string
}

// tslint:disable-next-line:no-any
type NavigationOptionsFn<TParams=any> = (props: NavigationScreenProps<TParams>) => NavigationStackScreenOptions

class Screen extends React.Component {
  // This should works fine
  static navigationOptions: NavigationOptionsFn<NavStateParams> = ({ navigation, screenProps }) => ({
    title: navigation.state.params.someValue
  })
}

您可能需要在某个

NavigationOptionsFn<TParams>
文件中声明
d.ts
类型,以使其在全局范围内工作。


4
投票

我认为使用

react-navigation
5.X 现在更简单了。以下是如何输入传递给屏幕/组件的提示
navigation
道具:

export default class Header extends React.Component<{
    navigation: StackNavigationHelpers;
}> {
...
}

Ps:使用这些版本进行测试

"@react-navigation/native": "^5.2.3",
"@react-navigation/stack": "^5.3.1",

3
投票
 yarn add --dev @types/jest @types/react-navigation

import { NavigationScreenProps } from "react-navigation";

export interface ISignInProps extends NavigationScreenProps<{}> { userStore: IUserStore }

export class SignInScreen extends React.Component { .... }

2
投票
public static navigationOptions: NavigationScreenConfig<NavigationStackScreenOptions> = 
    ({navigation}) => ({/* Your options... */})

2
投票

如果有人在扩展

NavigationScreenProps
时仍然遇到此问题,以便您可以正确键入
navigationOptions
等以及您自己的道具:

interface Props extends NavigationScreenProps {
  someProp: string;
  anotherProp: string;
}

export const SomeGreatScreen: NavigationScreenComponent<NavigationParams, {}, Props> = ({
  someProp,
  anotherProp,
}) => {
...
};

虽然

NavigationScreenComponent<Props>
导致解构属性
{ someProp, anotherProp }
出现类型错误,但无法识别 props 的扩展,而
NavigationScreenComponent<NavigationParams, {}, Props>
却做到了。这似乎是因为需要发送扩展的 props 类型作为第三个参数:

  export type NavigationScreenComponent<
    Params = NavigationParams,
    Options = {},
    Props = {}
  > = React.ComponentType<NavigationScreenProps<Params, Options> & Props> & {
    navigationOptions?: NavigationScreenConfig<Options>;
  };

来自

react-navigation.d.ts


1
投票

您可以在 Props 界面中直接扩展 NavigationScreenProps,而不是手动描述所有

导航功能
(例如:导航)。

就我而言,必须阻止 eslint 产生错误。

import { StackNavigator, NavigationScreenProps } from 'react-navigation';

export interface HomeScreenProps extends NavigationScreenProps {
/* your custom props here */
};

export class HomeScreen extends React.Component<HomeScreenProps, object> {

  render() {
    return (
      <View style={styles.container}>       
        <Button
          title="Go to Details"
          onPress={() => this.props.navigation.navigate('Details')}
        />
      </View>
    );
  }
}

1
投票

一个非常简单的解决方案

首先 将 RootStackParamList 类型和 PageProps 接口添加到您的导航器文件中

import * as React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import {
  createNativeStackNavigator,
  NativeStackNavigationProp,
} from '@react-navigation/native-stack';

import HomeScreen from './screens/Home';
import PasswordAddScreen from './screens/PasswordAdd';

export type RootStackParamList = {
  Home: undefined; // Add your props here
  PasswordAdd: undefined;
};

export interface PageProps<T extends keyof RootStackParamList> { // T is one of Home|PasswordAdd
  navigation: NativeStackNavigationProp<RootStackParamList, T>;
}

const Stack = createNativeStackNavigator<RootStackParamList>();

function Navigator() {
  return (
    <NavigationContainer>
      <Stack.Navigator screenOptions={{ headerShown: false }}>
        <Stack.Screen name="Home" component={HomeScreen} />
        <Stack.Screen name="PasswordAdd" component={PasswordAddScreen} />
      </Stack.Navigator>
    </NavigationContainer>
  );
}

export default Navigator;

然后,在您的组件或屏幕文件中添加

import React from 'react';
import { PageProps } from '../../Navigator';

function ItemsSeparator() {
  return <Divider my={1} bgColor="coolGray.50" />;
}

type Props = PageProps<'Home'>; // import and use the PageProps and pass the screen name - 
                                // exactly as it is in RootStackParamList

function HomeScreen({ navigation }: Props) {
  return (
    <Box safeArea bgColor="coolGray.100">
     ...
    </Box>
  );
}

export default HomeScreen;

完成。


0
投票

这似乎有效:

public static navigationOptions: NavigationScreenOptionsGetter<
  NavigationScreenOptions
> = (navigation, stateProps) => ({
  title: navigation.state.params.someValue,
});

0
投票

如果您的

does not work
tsconfig.json
,则
"strictNullChecks": true
部分包含错误。在这种情况下,你确实有一个错误,因为在行

navigation.state.params.someValue

params
是可选的。您可以做的是检查该值是否已在内部传递,否则提供默认值,例如:

title: navigation.state.params && navigation.state.params.someValue || 'Default title'


0
投票

或者如果您想制作 Custome 挂钩并将其导出 这是你可以做到的

import {
  NavigationProp,
  ParamListBase,
  useNavigation,
} from "@react-navigation/native";

export const useAppNavigation: () => NavigationProp<ParamListBase> = useNavigation;

并使用它

从您的路径导入 useAppNavigation 然后使用 as

const navigation = useAppNavigation();

const onPressSignUp = () => {
  navigation.navigate("SignUp");
};
© www.soinside.com 2019 - 2024. All rights reserved.