相關文檔:html
Redux官方:http://redux.js.org/react
RNRF(React-Native-Router-Flux)官方:https://github.com/aksonov/react-native-router-fluxandroid
1.Router git
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 |
Router相關:redux
https://github.com/aksonov/react-native-router-flux/blob/b11a84962e4e4d9265770382b8859d21d1a12ea0/README2.mdreact-native
2.Switchapp
必需要使用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>
使用unmountSceneside
執行順序:
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.PUSH or ActionConst.JUMP |
Defines how the new screen is added to the navigator stack. One of ActionConst.PUSH , ActionConst.JUMP , ActionConst.REPLACE , ActionConst.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 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.this.props
退出當前頁面,並刷新上一頁面
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,不然,下次進入的時候,仍是顯示上次的數據
目前給出的方案是:在退出組件的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,可是壞處也是顯而易見的,列表所有加載了一遍
辦法二: