React Native + Redux:什么是最好的和首选的导航?

时间:2016-08-09 04:25:11

标签: javascript html navigation react-native redux

我想将Redux用于React Native。目前我没有设置数据管理,因此index.ios.js具有以下内容:

  renderScene(route, navigator){
    this._navigator = navigator

    return (
        <route.component navigator={navigator} {...route.passProps}/>
    )
  }

<Navigator
  configureScene={this.configureScene}
  initialRoute={{name: 'Login', component: Login}}
  renderScene={(route, navigator) => this.renderScene(route, navigator)}
  style={styles.container}
  navigationBar={
    <Navigator.NavigationBar
      style={styles.navBar}
      routeMapper={NavigationBarRouteMapper}
    />
  }
/>

我打算切换到Redux。使用我当前的设置,不使用任何框架,只有例外是react-router,使用Redux导航的最佳方式是什么?使用存储,缩减器和操作的示例将非常有用。

2 个答案:

答案 0 :(得分:5)

编辑:现在应该使用react-navigation而不是NavigationExperimental。

-

我建议您使用NavigationExperimental而不是Navigator。最后一个是折旧的。 RN文档中有一个例子right here。它使用简单的减速器来管理您的导航状态。但是你也可以使用Redux处理这个状态,因为它是相同的逻辑。

这是我使用Redux和NavigationExperimental的标签设置:

navigator.js(注意:CardStack中的renderOverlay道具将在0.32中重命名为renderHeader)

import React from 'react';
import { NavigationExperimental } from 'react-native';
import { connect } from 'react-redux';
import { pop, push, selectTab } from './actions';

const {
  CardStack: NavigationCardStack,
} = NavigationExperimental;

class Navigator extends React.Component {
  constructor(props) {
    super(props);
    this._renderHeader = this._renderHeader.bind(this);
    this._renderScene = this._renderScene.bind(this);
  }

  _renderHeader(sceneProps) {
    return (
      <MyHeader
        {...sceneProps}
        navigate={this.props.navigate}
      />
    );
  }

  _renderScene(sceneProps) {
    return (
      <MyScene
        {...sceneProps}
        navigate={this.props.navigate}
      />
    );
  }

  render() {
    const { appNavigationState: { scenes, tabKey, tabs } } = this.props;

    return (
      <View style={{ flex: 1 }}>
        <NavigationCardStack
          key={`stack_${tabKey}`}
          navigationState={scenes}
          renderOverlay={this._renderHeader}
          renderScene={this._renderScene}
        />
        <Tabs
          navigationState={tabs}
          navigate={this.props.navigate}
        />
      </View>
    );
  }
}

const getCurrentNavigation = (navigation) => {
  const tabs = navigation.tabs;
  const tabKey = tabs.routes[tabs.index].key;
  const scenes = navigation[tabKey];
  return {
    scenes,
    tabKey,
    tabs,
  };
};

const mapStateToProps = (state) => {
  return {
    appNavigationState: getCurrentNavigation(state.navigation),
  };
};

const mapDispatchToProps = (dispatch) => {
  return {
    navigate: (action) => {
      if (action.type === 'pop') {
        dispatch(pop());
      } else if (action.type === 'push' && action.route) {
        dispatch(push(action.route));
      } else if (action.type === 'tab' && action.tabKey) {
        dispatch(selectTab(action.tabKey));
      }
    }
  };
};

export default connect(
  mapStateToProps,
  mapDispatchToProps,
)(Navigator);

actions.js

export function pop() {
  return ({
    type: 'POP_ROUTE',
  });
}

export function push(route) {
  return ({
    type: 'PUSH_ROUTE',
    route,
  });
}

export function selectTab(tabKey) {
  return ({
    type: 'SELECT_TAB',
    tabKey,
  });
}

reducer.js(注意:我在这里使用不可变,但是你可以使用适合你的任何东西

import { NavigationExperimental } from 'react-native';
import { Record } from 'immutable';

const {
  StateUtils: NavigationStateUtils,
} = NavigationExperimental;


export const InitialState = Record({
  // Tabs
  tabs: {
    index: 0,
    routes: [
      { key: 'tab1' },
      { key: 'tab2' },
      { key: 'tab3' },
    ],
  },
  // Scenes
  tab1: {
    index: 0,
    routes: [{ key: 'tab1' }],
  },
  tab2: {
    index: 0,
    routes: [{ key: 'tab2' }],
  },
  tab3: {
    index: 0,
    routes: [{ key: 'tab3' }],
  },
});
const initialState = new InitialState();


export default function navigation(state = initialState, action) {
  switch (action.type) {
    case 'POP_ROUTE': {
      const tabs = state.get('tabs');
      const tabKey = tabs.routes[tabs.index].key;
      const scenes = state.get(tabKey);
      const nextScenes = NavigationStateUtils.pop(scenes);

      if (scenes !== nextScenes) {
        return state.set(tabKey, nextScenes);
      }
      return state;
    }

    case 'PUSH_ROUTE': {
      const route = action.route;
      const tabs = state.get('tabs');
      const tabKey = tabs.routes[tabs.index].key;
      const scenes = state.get(tabKey);
      const nextScenes = NavigationStateUtils.push(scenes, route);

      if (scenes !== nextScenes) {
        return state.set(tabKey, nextScenes);
      }
      return state;
    }

    case 'SELECT_TAB': {
      const tabKey = action.tabKey;
      const tabs = state.get('tabs');
      const nextTabs = NavigationStateUtils.jumpTo(tabs, tabKey);

      if (nextTabs !== tabs) {
        return state.set('tabs', nextTabs);
      }
      return state;
    }

    default:
      return state;
  }
}

最后,在 MyScene.js 组件中,您可以通过测试当前路径(例如使用开关)来处理要显示的组件。 通过在组件中传递导航功能,您可以管理您的场景(即:this.props.navigate({type:&#39; push&#39;,route:{key:&#39} ;搜索&#39;}}))。

请注意,您可以按照自己的意愿处理自己的状态和行为。理解的主要思想是如何减少状态,无论你是否使用redux。

答案 1 :(得分:2)

我建议您将react-navigation用于原生和网络环境,replace NavigationExperimental只需查看以下example

  • 为iOS和Android构建的组件
  • 在移动应用,网络应用和服务器呈现之间共享导航逻辑。
  • Documentation非常简单
  • 开发自己的navigation views
  • 很容易!

只需在您的应用中定义导航。

import {
  TabNavigator,
} from 'react-navigation';

const BasicApp = TabNavigator({
  Main: {screen: MainScreen},
  Setup: {screen: SetupScreen},
});

...并导航

class MainScreen extends React.Component {
  static navigationOptions = {
    label: 'Home',
  };
  render() {
    const { navigate } = this.props.navigation;
    return (
      <Button
        title="Go to Setup Tab"
        onPress={() => navigate('Setup')}
      />
    );
  }
}

并执行以下操作以添加redux,只需定义您的reducer ...

const AppNavigator = StackNavigator(AppRouteConfigs);

const appReducer = combineReducers({
  nav: (state, action) => (
    AppNavigator.router.getStateForAction(action, state)
  )
});

...并使用addNavigationHelpers

在您的组件中导航
  <AppNavigator navigation={addNavigationHelpers({
    dispatch: this.props.dispatch,
    state: this.props.nav,
  })} />