相关文档: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,可是坏处也是显而易见的,列表所有加载了一遍
办法二: