zoukankan      html  css  js  c++  java
  • React Native之router-flux的使用

    相关文档:

    Redux官方:http://redux.js.org/

    RNRF(React-Native-Router-Flux)官方:https://github.com/aksonov/react-native-router-flux

    1.Router 

    PropertyTypeDefaultDescription
    reducer function   optional user-defined reducer for scenes, you may want to use it to intercept all actions and put your custom logic
    createReducer function   function that returns a reducer function for {initialState, scenes} param, you may wrap Reducer(param) with your custom reducer, check Flux usage section below
    other props     all properties that will be passed to all your scenes
    children   required (if no scenes property passed) Scene root element
    scenes object optional scenes for Router created with Actions.create. This will allow to create all actions BEFORE React processing. If you don't need it you may pass Scene root element as children
    getSceneStyle function optional Optionally override the styles for NavigationCard's Animated.View rendering the scene.
    backAndroidHandler function optional Optionally override the handler for BackAndroid, return true to stay in the app or return false to exit the app. Default handler will pop a scene and exit the app at last when the back key is pressed on Android.
    onBackAndroid function optional Get called after back key is pressed and a scene is poped, won't affect the default behavior.
    onExitApp function optional

    Optionally override the default action after back key is pressed on root scene. Return true to stay, or return false to exit the app.

    Router相关:

         https://github.com/aksonov/react-native-router-flux/blob/b11a84962e4e4d9265770382b8859d21d1a12ea0/README2.md

    2.Switch

    必须要使用tabs={true},否则会找不到unloginCenter的错误

    <Scene
                                key="switch"
                                component={connect(state=>({login:state.loginReducer.login}))(Switch)}
                                title={Consts.UserCenterPage}
                                tabs={true}
                                unmountScenes
                                // hideOnChildTabs
                                selector={props=>props.login?'tabbar':'unloginCenter'}
                            >
        <Scene key="tabbar" />
        <Scene key="unloginCenter" />
    </Scene>

    使用unmountScenes

    执行顺序:

    tabbar

    unloginCenter
    unloginCenter
    -----登录
    tabbar

    不使用unmountScenes
    unloginCenter
    unloginCenter
    -----登录
    tabbar
    tabbar


    3.Scene

    既可以作为场景又可以用作场景容器,如果未设置Component时,是作为容器使用的,加载子节点中包含initial属性的Scene,如果没有任何Scene有该属性,则加载第一个Scene

    容器中的Scene可以相互跳转

    clone属性用用于不同层级之间的跳转

    PropertyTypeDefaultDescription
    key string required Will be used to call screen transition, for example, Actions.name(params). Must be unique.
    component React.Component semi-required The Component to be displayed. Not required when defining a nested Scene, see example. If it is defined for 'container' scene, it will be used as custom container renderer
    initial bool false Set to true if this is the initial scene
    type string ActionConst.PUSHor ActionConst.JUMP Defines how the new screen is added to the navigator stack. One of ActionConst.PUSHActionConst.JUMPActionConst.REPLACEActionConst.RESET. If parent container is tabbar (tabs=true), ActionConst.JUMP will be automatically set.
    clone bool   Scenes marked with clone will be treated as templates and cloned into the current scene's parent when pushed. See example.
    passProps bool false Pass all own props (except style, key, name, component, tabs) to children. Note that passProps is also passed to children.

    在Component中获取Scene的属性和方法(https://github.com/aksonov/react-native-router-flux/issues/1109)

    var tabSceneMenu = {
          onLeft :()=>{ MenuActions.openMenu() },
          leftButtonImage:leftImage,
          getLeftTitle:this.getLeftTitle, 
          getRightTitle:this.getRightTitle,
          onRight :()=>{MenuActions.openRightMenu();} 
        }
    
    <Scene key="newTab" {...tabSceneMenu} passProps={true} component={YourComponent} title="Title" ></Scene>

     直接在Component中获取当前的Scene

    https://github.com/aksonov/react-native-router-flux/blob/master/docs/REDUX_FLUX.md

    4.Modal

    To display a modal use Modal as root renderer, so it will render the first element as normal scene and all others as popups (when they are pushed). For example:

    这种用法主要添加一个全局的Modal对话框,该Scene可以覆盖在所有的其他Scene之上(注意:必须设置该Scene的position:'absolute',否则会该Scene会从底部显示挤占屏幕)

    import StatusModal from './components/StatusModal'
    
    <Router>
      <Scene key="modal" component={Modal} >
        <Scene key="root">
          <Scene key="screen1" initial={true} component={Screen1} />
          <Scene key="screen2" component={Screen2} />
        </Scene>
        <Scene key="statusModal" component={StatusModal} />
      </Scene>
    </Router>

    5.Actions

    RNRF里面的类,平时主要有三个操作

    Actions.ACTION_NAME(PARAMS) will call the appropriate action and params will be passed to the scene.all params will be part of this.props for given Scene component
    Actions.pop() will pop the current screen. It accepts following optional params:
    {popNum: [number]} allows to pop multiple screens at once
    {refresh: {...propsToSetOnPreviousScene}} allows to refresh the props of the scene that it pops back to,会导致上一个界面重新render一次,即使这个属性前面不存在,只pop的话不会重新render
    Actions.refresh(PARAMS) will update the properties of the current screen.

    退出当前页面,并刷新上一页面

    Actions.pop({ refresh: { test: true }})

    https://github.com/aksonov/react-native-router-flux/issues/1381

    同时操作的问题(设置setTimeout可以解决)

    https://github.com/aksonov/react-native-router-flux/issues/1266

    https://github.com/aksonov/react-native-router-flux/issues/1341(解决办法)

    获取navigationnStack和栈顶的Scene(官方没实现)

    https://github.com/aksonov/react-native-router-flux/issues/1345(测试,暂未发现问题)

    6.可设置的全局属性

    注意:Router Scene中的属性修改在Hot Reloading中无效的,必须Reload

    navigationBarStyle  titleStyle在Router中设置,全局生效,可以在Scene中进行覆盖

    7.清空Reducer的State

    发生情况:提出页面后,需要清空connect的Reducer中的State,否则,下次进入的时候,还是显示上次的数据

    https://www.v2ex.com/t/300257

    http://stackoverflow.com/questions/35622588/how-to-reset-the-state-of-a-redux-store/39581166#39581166

    目前给出的方案是:在退出组件的componentWillUnmount事件中,发送一个action,通知reducer还原对应的属性

    8.About Key xxx is already defined

    There is no way to prevent Router re-render IF you wrap it under a Provider AND listen updates from redux. It is a nature by design.
    
    the point how to prevent this, is: Router should render once and just once it means:
    
    If you didn't connect to redux at all, it works fine since your Router would not be triggered by any of updates from redux.
    
    Also, you can connect() Router to redux to get a dispatch() method props but you can NOT listen to another props.
    简单的说,就是别再有Router的界面connect的时候绑定属性,因为这样会引发componentWillReceiveProps....-render,而Router是只能渲染一次的,这个在设计的时候就这样
    所以可以绑定事件,但千万别绑定属性

    9.tabbar

    Every tab has its own navigation bar. However, if you do not set its parent <Scene tabs={true} /> with hideNavBar={true}, the tabs' navigation bar will be overrided by their parent.

    <Scene key="myTabBar" tabs={true} hideNavBar tabBarStyle={style.tabBarStyle}>
      <Scene 
        key="myTab" 
        title="My Tab" 
        icon={MyTabIcon} 
        onPress={()=> {
          Actions.myTab_1({type: ActionConst.REFRESH});
        }}
       >
          <Scene key="myTab_1" component={MyTabComponent} hideNavBar/>
      </Scene>
    </Scene>

    主要讲一下NavBar和TabBar,如果这种写的话,会发现,界面里面的内容直接覆盖到顶部的tabbar了,可以在每个tab页设置marginBottom,或者用更通用的,对router设置getSceneStyle

    // define this based on the styles/dimensions you use
    const getSceneStyle = (/* NavigationSceneRendererProps */ props, computedProps) => {
        const style = {
            flex: 1,
            backgroundColor: '#fff',
            shadowColor: null,
            shadowOffset: null,
            shadowOpacity: null,
            shadowRadius: null,
        };
        if (computedProps.isActive) {
            style.marginTop = computedProps.hideNavBar ? (Platform.OS==='android'?0:20) : (Platform.OS==='android'?54:64);
            style.marginBottom = computedProps.hideTabBar ? 0 : 50;
        }
        return style;
    };

    看上面的代码就是android默认的是0/54(有/无NavBar),iOS默认的是20/54(有/无NavBar,因为iOS的窗口默认的大小是包含状态栏的,android的默认是不包括的)

    底部的tabbar的高度固定为50

    未解决/已解决问题:

    1)怎么将navigationBar上面按钮的点击事件传递到component中去

    rightButtonRender全部是在Scene中设置的,怎么传递?

    https://github.com/aksonov/react-native-router-flux/issues/979(没有)

    解决办法:全局订阅/发布方法

    https://facebook.github.io/react-native/docs/native-modules-android.html

    http://www.ghugo.com/react-native-event-emitter/

    http://blog.csdn.net/syg90178aw/article/details/50964947?locationNum=7

    https://github.com/facebook/react-native/issues/2819

    2)对多个modal页面的管理问题

    由于modal始终在栈的最顶层,如果在顶部未消失并且unFocus的情况下,可能会出现modal始终存在,执行Actions.pop();modal底部的页面持续出栈的情况

    目前暂时没有什么好的解决办法,只能将那些Dialog直接写在Component中

    3)怎么动态的改变Scene上面的title/状态栏上面的button

    https://github.com/aksonov/react-native-router-flux/issues/1307

    我们知道,Props在组件的内部是无法被改变的,只能通过外部改变

    由于title最终会成为component的属性,所以可以再component中直接使用Actions.refresh({title:''});来刷新title

    用这种办法,render会被调用两次,也可以通过该方法来改变onBack事件,其他能改的属性大致可以通过下图来判断

    已测试:可以直接通过Actions.refresh({rightButtonRender:})来刷新右上角的按钮

    4)在tabbar显示消息数

    https://github.com/aksonov/react-native-router-flux/issues/1362

    5.在某个界面安卓下禁用返回按钮

    https://github.com/aksonov/react-native-router-flux/issues/1316

    6.跳转动画

    https://github.com/aksonov/react-native-router-flux/issues/1202

    modal动画,官方是没有相关的实现的,别人也是推荐自定义,下面的例子测试有点问题,说什么transitionY必须为number,但是的确是照着例子来的

    https://github.com/aksonov/react-native-router-flux/issues/187

    https://github.com/sbycrosz/react-native-router-flux/commit/1a386d16b273e42f838e805fbee0e3a63cc9158f

    7.从列表界面跳转到详情界面,详情界面提交成功后,返回到列表界面的时候刷新列表

     1)通过Actions.pop({refresh:{}}) 传递一个变化的状态,在详情界面的componentWllReceiveProps方法里边比较然后调用刷新接口

     2)redux:在跳转的时候,将列表界面的请求参数对象和Model对象都传递到详情界面,详情界面通过redux提交后,直接在成功的回调方法里面,重新dispatch刷新列表的方法(但是按照当前的逻辑,提交成功后)

     3)使用EventEmitter来传递数据

    8.页面跳转

    出现了下面的情况,A->B->A,这样是无法跳转的,也就是说从tabbar跳转到login,然后再跳转到tabbar,此时无法跳转,目前原因未知

    9.连续操作

    对设置为type='modal'的Scene,譬如loading,显示后,马上pop,此时pop掉的并不是loading页面,而是上一个页面(猜测异步跳转是需要时间的,此时loading还没有创建)

    10.redux和RefreshControl的配合使用

     前面没使用Redux之前,获取数据直接在Component里面来操作,可以很方便的控制State的刷新属性(譬如isLoading)的值来控制是否显示刷新

     但是改为Redux模式之后,接口的调用相当于异步了,你无法知道什么时候界面刷新完成

     1)在componentWillReceiveProps方法中来判断dataList(接口获取到的数据,使用redux绑定到component中)是否发生变化来判断,如果发生变化,则将isLoading设为false

       但是现在发现一个问题,当接口获取成功(即使没数据)时是会触发的,但是调用失败的时候,reducer里面直接返回原来的数据,并不会触发原来component里面的componentWillReceiveProps方法,也就是说refreshControl一直是刷新的状态

       一般情况下,调用接口失败是不会清空上一次的数据的(大部分的App都是如此设计)

       办法一:可以将dataList:{...state.dataList}这样返回一个同上次同样的数据来刷新触发componentWillReceiveProps,但是坏处也是显而易见的,列表全部加载了一遍

       办法二:

  • 相关阅读:
    UVA 10480 Sabotage (最大流最小割)
    bzoj2002 [Hnoi2010]Bounce 弹飞绵羊 (分块)
    poj3580 SuperMemo (Splay+区间内向一个方向移动)
    bzoj1500: [NOI2005]维修数列 (Splay+变态题)
    hdu3436 Queue-jumpers(Splay)
    hdu4710 Balls Rearrangement(数学公式+取模)
    hdu1890 Robotic Sort (splay+区间翻转单点更新)
    zoj2112 Dynamic Rankings (主席树 || 树套树)
    poj3581 Sequence (后缀数组)
    notepa++ Emmet的安装方法
  • 原文地址:https://www.cnblogs.com/yz1311/p/6086234.html
Copyright © 2011-2022 走看看