【问题标题】:Add strong typing for react navigation props为反应导航道具添加强类型
【发布时间】:2018-06-04 02:29:23
【问题描述】:

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

该项目使用 react-navigation,所以在我的屏幕上我可以设置 navigationOptions 并且我可以访问 prop 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
    })
}

将 react-navigation 作为组件的 props 处理的最佳方法是什么。

【问题讨论】:

    标签: typescript react-native react-navigation


    【解决方案1】:

    只需将 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>
            );
          }
        }
    

    【讨论】:

    • 但是如果我要从其他组件(比如App.tsx)导入HomeScreen 组件,我将不得不提供navigation 属性。我该如何避免呢?
    • 在您的顶级组件中,使用 withNavigation 函数提供这些道具reactnavigation.org/docs/en/with-navigation.html
    • 我还没有找到将withNavigation 与打字稿一起使用的方法,因为它还需要一个额外的导航道具。我有另一个问题。 stackoverflow.com/questions/51585890/…
    • 所有这一切都是在实例方法中为props.navigation 提供类型,这在原始问题中已经实现。问题是 1) 如何在 navigationOptions 静态方法中获取 navigation 的类型,以及 2) 如何获取导航状态下可用参数的类型。
    • 如上图所示为道具添加导航后,我将组件导出为export default connect(mapStateToProps, mapDispatchToProps)(withNavigation(MyComponent));,这解决了MyComponent缺少道具的打字稿投诉
    【解决方案2】:

    如果您传递的是由

    定义的navigation prop
    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 = {
    
       Pdp: undefined; //current screen
    
       PdpComments: {slug: string}; // a screen that we are 
    // navigating to, in the current screen,
    // that we should pass a prop named `slug` to it
    
       Sellers: {data: Array<string>};
    
       Favorites: undefined; // a screen that we are navigating to 
    // in the current screen, that we don't pass any props to it
    };
    
    interface IPdpPageProps {
       navigation: NativeStackNavigationProp<RootStackParamList, 'Pdp'>;
    }
    
    // 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}: IPdpPageProps) {
       return ...
    }
    

    【讨论】:

    • 这是 IMO 的最佳解决方案。简单,像魅力一样工作
    • 这看起来很完美,但您可以添加一个最小的细节示例。这将非常有帮助
    • @AliYarKhan 我提供了一个更好的方法来匹配react-navigation 版本6.x 中的最新更新
    【解决方案3】:

    这行得通:

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

    【讨论】:

      【解决方案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",
      

      【讨论】:

      • 在这种情况下我们如何调用navigation.setOptions()?它说Property 'setOptions' does not exist on type 'StackNavigationHelpers'
      • @highjump 是的,正确,需要寻找替代解决方案。
      【解决方案5】:

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

      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&lt;TParams&gt; 类型声明到某个d.ts 文件中以使其在全局范围内工作。

      【讨论】:

        【解决方案6】:
         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 { .... }
        

        【讨论】:

          【解决方案7】:
          public static navigationOptions: NavigationScreenConfig<NavigationStackScreenOptions> = 
              ({navigation}) => ({/* Your options... */})
          

          【讨论】:

          • 它是navigationOptions 的最佳解决方案,它支持箭头功能和对象,谢谢,还要注意使用NavigationScreenOptions 而不是NavigationStackScreenOptions
          【解决方案8】:

          如果有人在扩展 NavigationScreenProps 时仍然遇到此问题,那么您可以正确输入 navigationOptions 等以及您自己的道具:

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

          NavigationScreenComponent&lt;Props&gt; 导致解构属性{ someProp, anotherProp } 的类型错误,无法识别道具的扩展,NavigationScreenComponent&lt;NavigationParams, {}, Props&gt; 做到了。这似乎是由于需要将扩展​​的 props 类型作为第三个参数发送:

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

          来自react-navigation.d.ts

          【讨论】:

            【解决方案9】:

            您可以在 Props 的界面中直接扩展 NavigationScreenProps,而不是手动描述所有 navigation functions(例如:导航)。

            就我而言,必须阻止 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>
                );
              }
            }
            

            【讨论】:

              【解决方案10】:

              这似乎有效:

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

              【讨论】:

              • 似乎 NavigationScreenOptionsGetter 是为此目的而制作的,但它不起作用。正如您在此处看到的:reactnavigation.org/docs/en/headers.html navigationOptions 函数接受一个对象。
              【解决方案11】:

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

              navigation.state.params.someValue

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

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

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2020-04-07
                • 2021-06-13
                • 1970-01-01
                • 2020-10-22
                • 2021-08-29
                • 2021-06-20
                • 2020-04-24
                相关资源
                最近更新 更多