React Navigation

安装

npm install react-navigation @rematch/react-navigation

对于 @rematch/core@0.x 使用 @rematch/react-navigation@1.1.0

示例

参看一个例子

设置

使用Redux设置React-Navigation是一个多步骤过程。 希望这个插件简化了这个过程。

  1. 创建你的<Routes />,然后选择你的 initialRouteName 的名称。

// Routes.js
export default StackNavigator(
  {
    Landing: {
      screen: Screen.Landing,
    },
    Login: {
      screen: Screen.Login,
    },
    App: {
      screen: App,
    },
  },
  {
    initialRouteName: 'Landing',
  }
)

2. 传递 Routes initialRouteName 进入 createReactNavigationPlugin

// index.js
import { init, dispatch } from '@rematch/core'
import createReactNavigationPlugin from '@rematch/react-navigation'
import * as ReactNavigation from 'react-navigation'
import Routes from './Routes'

// add react navigation with redux
const { Navigator, reactNavigationPlugin } = createReactNavigationPlugin({
  Routes,
  initialScreen: 'Landing'
})

const store = init({
  plugins: [reactNavigationPlugin],
})

export default () => (
  <Provider store={store}>
    <Navigator />
  </Provider>
)

3. 使用包含 navigation helpers 的插件来简化派发 Navigation action。

// included in plugin
dispatch.nav.navigate = (action) => dispatch(NavigationActions.navigate(action))
dispatch.nav.reset = (action) => dispatch(NavigationActions.reset(action))
dispatch.nav.back = (action) => dispatch(NavigationActions.back(action))
dispatch.nav.setParams = (action) => dispatch(NavigationActions.setParams(action))

4. 只需传递 NavigationAction 选项即可。

// somewhere in your app
import { dispatch } from '@rematch/core'

dispatch.nav.navigate({ routeName: 'Login' })

如有必要,导入NavigationActions

import { dispatch } from '@rematch/core'
import { NavigationActions } from 'react-navigation'

const resetAction = dispatch.navigate.reset({
  index: 1,
  actions: [
    NavigationActions.navigate({ routeName: 'Profile'}),
    NavigationActions.navigate({ routeName: 'Settings'})
  ]
})

Back Handler

使用react-navigation设置Android后退按钮处理的示例。

import { dispatch, init } from '@rematch/core'
import createReactNavigation from '@rematch/react-navigation'
import React from 'react'
import { BackHandler } from 'react-native'
import { Provider } from 'react-redux'
import { Routes } from './Routes'

export class App extends React.Component {
  componentDidMount() {
    BackHandler.addEventListener('hardwareBackPress', this.handleBack)
  }

  componentWillUnmount() {
    BackHandler.removeEventListener('hardwareBackPress', this.handleBack)
  }
  
  handleBack = () => {
    if (store.getState().nav.index === 0) {
      BackHandler.exitApp()
    }
    dispatch.nav.back()
    return true
  }

  render() {
    return (
      <Provider store={store}>
        <Navigator />
      </Provider>
    );
  }
}

Selectors

你可能会发现将一些自定义selector添加到你的nav model是有帮助的。您可以通过创建一个nav model配置对象来轻松添加selector。这个例子将添加一个currentRouteName选择器:

// models/nav.js
export default {
  selectors: {
    currentRouteName(state) { return state.routes[state.index].routeName; },
  },
}

将上面的 model 添加到您的Rematch配置中:

// models/index.js
export { default as nav } from './nav'

确保您的新 model 包含在您的init中:

import { select } from '@rematch/select'
import * as models from './models'

const store = init({
  models,
  plugins: [select, reactNavigationPlugin],
});

当然,你还需要安装 Rematch Select 插件

现在你将有能力在你的app内调用select.nav.currentRouteName(state),参阅 Rematch Select 插件文档 以获取更多关于配置和使用的selector。

Immutable JS and other non-{ } Stores

如果您的 store 不是标准的Javascript对象{},那么您可能需要将 sliceState 配置传递给createReactNavigationPlugin。该函数获取状态并返回包含React Navigation对象的状态片段。它在Navigator中用于将 state 映射到其属性,并用于侦听 navigation state 更改的中间件。默认情况下使用state.nav,在大多数情况下它可以正常工作。

如果你的 store 是一个 Immutable JS 对象,你可能需要传递 sliceState: state => state.get('nav') 作为 createReactNavigationPlugin 的配置。这里有一个小例子:

// index.js
import { init, dispatch } from '@rematch/core'
import createReactNavigationPlugin from '@rematch/react-navigation'
import * as ReactNavigation from 'react-navigation'
import Routes from './Routes'
import { combineReducers } from 'redux-immutable';
import { Map } from 'immutable';

// add react navigation with redux
const { Navigator, reactNavigationPlugin } = createReactNavigationPlugin({
  Routes,
  initialScreen: 'Landing',
  sliceState: state => state.get('nav')  // Returns Immutable JS slice
})

const store = init({
  initialState: fromJS({}),
  plugins: [reactNavigationPlugin],
  redux: {
    initialState: Map(),              // Initializes a blank Immutable JS Map
    combineReducers: combineReducers, // Combines reducers into Immutable JS collection
  },
})

export default () => (
  <Provider store={store}>
    <Navigator />
  </Provider>
)

在上面的例子中,你的 store 是一个Immutable JS对象。但是,商店的nav切片是标准的 JS 对象。我推荐这种方法,因为 React Navigation 导航器和 Redux 中间件期望导航状态是一个标准的 JS 对象。这是最高效的方法。另一种方法是将导航状态存储为不可变 JS 映射,每次导航器或中间件需要访问 Rematch 状态时都需要调用 fromJS() toJS(),这会导致性能下降。

Last updated