Maps react-navigation props to your screen components directly
Clone or download
Latest commit 089692c Sep 13, 2018
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
LICENSE Create LICENSE Jul 24, 2017
README.md Update README.md Sep 13, 2018
index.js Safely get nested navigation params (#6) Jun 19, 2018
package.json 0.3.0 Jun 19, 2018

README.md

react-navigation-props-mapper

yarn add react-navigation-props-mapper

or

npm i react-navigation-props-mapper

Motivation

You're using react-navigation to navigate around your React Native app. The documentation describes you should use this.props.navigation.getParam(paramName, defaultValue) or alternatively this.props.navigation.state.params to access props passed to your screen. For example:

render() {
  // The screen's current route is passed in to `props.navigation.state`:
  const { params } = this.props.navigation.state;
  return (
    <View>
      <Text>Chat with {params.user.userName}</Text>
    </View>
  );
}

This works well but if you don't want your code to be tightly coupled to react-navigation (maybe because you're migrating from another navigation lib) or if you simply want to work with navigation params the same way as with any other props (and have them typed), this package will help.

withMappedNavigationProps

Use this function to be able to access the props passed to your screen directly. Eg. instead of this.props.navigation.state.params.user.userName you'd write this.props.user.userName. The function wraps the provided component in a HOC and passes everything from props.navigation.state.params as well as props.screenProps to the wrapped component.

Usage

When defining the screens for your navigator, wrap the screen component with the function. For example:

import { withMappedNavigationProps } from 'react-navigation-props-mapper'

@withMappedNavigationProps()
export default class SomeScreen extends Component {

// if you don't want to use decorators:
export default withMappedNavigationProps()(SomeScreen)

withMappedNavigationAndConfigProps

When using a function in static navigationOptions to configure eg. a screen header dynamically based on the props, you're dealing with the same issues as mentioned above. withMappedNavigationAndConfigProps does the same as withMappedNavigationProps but also saves you some hassle when defining screen's static navigationOptions property. For example, it allows turning

static navigationOptions = ({ navigation }) => ({
  title: `${navigation.state.params.name}'s Profile!`,
  headerRight: (
      <HeaderButton title="Sort" onPress={() => navigation.navigate('DrawerOpen')} />
    ),
});

into

static navigationOptions = ({ navigation, name }) => ({
  title: `${name}'s Profile!`,
  headerRight: (
      <HeaderButton title="Sort" onPress={() => navigation.navigate('DrawerOpen')} />
    ),
});

Usage

import { withMappedNavigationAndConfigProps } from 'react-navigation-props-mapper' and use the same way as withMappedNavigationProps. In your screen component, use static navigationOptions, same as you'd do normally.

Injecting Additional Props to Your screen

Consider the deep linking guide from react-navigation. You have a chat screen defined as:

Chat: {
    screen: ChatScreen,
    path: 'chat/:userId',
  },

you may need to use the userId parameter to get the respective user object and do some work with it. Wouldn't it be more convenient to directly get the user object instead of just the id? Both withMappedNavigationAndConfigProps and withMappedNavigationProps accept an optional parameter, of type ReactClass (a react component) that gets all the navigation props and the wrapped component as props. You may do some additional logic in this component and then render the wrapped component, for example:

import React from 'react';
import { inject } from 'mobx-react/native';
import { withMappedNavigationAndConfigProps } from 'react-navigation-props-mapper';

class AdditionalPropsInjecter extends React.Component {
  // In this component you may do eg. a network fetch to get data needed by the screen component.
  // Once you have the data ready, you may also need to call `setParams`.
  render() {
    const { WrappedComponent, userStore, userId } = this.props;

    const additionalProps = {};
    if (userId) {
      additionalProps.user = userStore.getUserById(userId);
    }
    return <WrappedComponent {...this.props} {...additionalProps} />;
  }
}

@inject('userStore') //this injects userStore as a prop, via react context
@withMappedNavigationAndConfigProps(AdditionalPropsInjecter)
class ChatScreen extends React.Component {}

That way, in your ChatScreen component, you don't have to work with user id, but directly work with the user object.

Tip

If you don't like the function names, you may import the functions with an alias:

import { withMappedNavigationAndConfigProps as mapperFunc } from 'react-navigation-props-mapper';