新轮子:整合Navigator和React Router使用URL导航页面



  • 最近新项目开发完成上架,顺手造了个新轮子,用来整合Navigator和ReactRouter两个组件。可以实现通过URL方式来管理和导航页面。

    GitHub:https://github.com/starlight36/react-native-navigator-router
    NPM:https://www.npmjs.com/package/react-native-navigator-router

    使用方式很简单,只需要一点点配置:

    import React, { Component } from 'react';
    import { AppRegistry } from 'react-native';
    import { createMemoryHistory, Router, IndexRoute, Route } from 'react-router';
    import { createNavigatorRouter } from 'react-native-navigator-router';
    
    class App extends Component {
      render() {
        return (
          <Router history={createMemoryHistory('/')}>
            <Route path='/' component={createNavigatorRouter()}>
              <IndexRoute component={Home} />
              <Route path="/about" component={About} />
              <Route path="/detail" component={Detail} />
            </Route>
          </Router>
        );
      }
    }
    
    AppRegistry.registerComponent('Example', () => App);
    

    要调用一个页面,只需要:

    this.context.router.push('/about');
    

    目前可以支持push、back、go、replace操作,其他方式尚未测试。可以跟Redux整合起来使用。

    欢迎使用并反馈问题。效果上图(GIF动图7.1M,手机慎点)



  • 先mark,菜鸟表示目前还没理解RN和react-route的关系



  • 不错,很赞………………………………



  • 能说明用 url 导航有什么好处吗?



  • @zhiquan_yu 简单的说就是解耦合,用URL替代页面跳转的相互调用,具体来说这个组件也没有什么,大概三点:

    1. 纯Navigator导航每个页面组件都依赖Navigator引用,当前页面要负责创建要跳转的页面对象,从最小知识原则和单一职责原则来看这一做法都不是较为科学的方案。通过Router对页面进行统一配置,通过URL转跳,降低了组件之间的耦合程度,更容易维护。

    2. 对推送、动态模块等更友好。由于页面跳转、动画等都只需要一个简单的URL参数,所以可以很简单地实现推送打开到任意落地页,也能轻松实现动态定义页面菜单控制跳转到任意页,甚至配合Linking组件实现自定义schema跳转任意页。

    3. 对数据分析数据统计友好。App内可以非常方便地获取页面跳转路径、计算页面停留时间、跟踪页面入口按钮等。

    如果说还有一点优势,那就是对Web前端的程序员们更加友好,这个对他们来说是很大的便利啊。

    但是这些都是次要的,主要的就是三件事情。很惭愧,就做了一点微小的工作,谢谢大家!



  • 但是这种有个问题,手势右滑返回没法触发 redux



  • @郁也风 谢谢提问。手势后退事件是支持的,我解决了这个问题。代码在这里。后退触发Redux的目的其实是为了同步Navigator和Router两个页面栈。由于这个组件设定为不强制依赖Redux,所以后退手势之后同步栈的工作直接调用Router完成,即使与React Router Redux配合也没有问题。后期版本我可以把后退事件暴露出来,就能自定义一些处理了。



  • 表示 还是线运行下例子看看, 感觉如果跟tabbarios 再结合下 应该更不错 运行看例子去了



  • @starlight36 说:

    目前可以支持push、back、go、replace操作,

    发现 在使用back的时候提示back方法不存在 更换为goBack可以,是不是这里写错了是goBack不是back?



  • @hainuo 这里指的不是方法,是操作。具体可以参考React Router的文档。



  • @starlight36 恩 如果是回到上一页我可以用goBack 如果回到前2页 可以用go('-2') 如果是直接到某一个页面可以使用replace('/about')



  • 有没有和reduxtab整合的例子?



  • @kaenry 你是指的tabbarios吗? https://github.com/hainuo/react-native-navigator-router-and-TabBarIOS 我这里有一个简单的例子 不知道是不是你需要的



  • @hainuo 主要是redux不知道怎么结合你这个导航用



  • @kaenry https://github.com/reactjs/react-router-redux 我仅仅能够看懂redux 还不会写 , 不过这个教程写的也不错



  • @starlight36 楼主还在不 安卓的物理返回键报错 。能帮忙看下不
    0_1474200703841_QQ20160918-1@2x.png



  • @随风远行 贴一下你的代码吧



  • import React, { Component } from 'react';
    import { Text, View, TouchableHighlight, StyleSheet, BackAndroid } from 'react-native';
    import { Provider } from 'react-redux';
    import configureStore from './store/store';
    import { createMemoryHistory, Router, IndexRoute, Route } from 'react-router';
    import { createNavigatorRouter } from 'react-native-navigator-router';

    import Home from './containers/Home';
    import Detail from './pages/FeedDetail';
    import SearchContainer from './containers/SearchContainer';

    const store = configureStore();

    class App extends Component {

    render() {
        return (
            <Router history={createMemoryHistory('/')}>
                <Route path='/' component={createNavigatorRouter()}>
                    <IndexRoute component={Home} />
                    <Route path="/detail/:link" component={Detail} />
                    <Route path="/search/:type" component={SearchContainer} />
                </Route>
            </Router>
        );
    }
    

    }

    const Root = () => (
    <Provider store={store}>
    <App />
    </Provider>
    );

    export default Root;
    @starlight36



  • handleBackButton() {
    /*for (let i = this.backHandlers.length - 1; i >= 0; i--) {
    if (this.backHandlersi) {
    return true;
    }
    }

      const { navigator } = this.refs;
      if (navigator) {
        this.context.router.goBack();
        return true;
        //return this.props.onBack.apply(this, [navigator.getCurrentRoutes().length]);
      }
    
      return false;*/
      //@todo 待修改
      const nav = this.refs.navigator;
      const routers = nav.getCurrentRoutes();
      if (routers.length > 1) {
        const top = routers[routers.length - 1];
        if (top.ignoreBack || top.component.ignoreBack){
          // 路由或组件上决定这个界面忽略back键
          return true;
        }
        const handleBack = top.handleBack || top.component.handleBack;
        if (handleBack) {
          // 路由或组件上决定这个界面自行处理back键
          return handleBack();
        }
        // 默认行为: 退出当前界面。
        nav.pop();
        return true;
      }else{
        if (this.lastBackPressed && this.lastBackPressed + 2000 >= Date.now()) {
          //最近2秒内按过back键,可以退出应用。
          return false;
        }
        this.lastBackPressed = Date.now();
        ToastAndroid.show('再按一次退出应用',ToastAndroid.SHORT);
        return true;
      }
    }
    

    组件里面改了这里就OK了。


Log in to reply