React Native之router-flux的使用


相關文檔:

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

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

 

1.Router 

Property Type Default Description
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屬性用用於不同層級之間的跳轉

Property Type Default Description
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,但是壞處也是顯而易見的,列表全部加載了一遍

   辦法二:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM