react-navigation及dva使用(三)
来源:互联网 发布:好用的男士爽肤水 知乎 编辑:程序博客网 时间:2024/06/08 17:00
关于react-navigation,由于是社区维护的路由库,所以更新和问题会比较多,版本更新也比较快,我用的2个版本比较多,一个是beta7版本,现在master是beta11(截止到7月4日为止),关于react-navigation和redux进行绑定,看个人项目及偏好,这是牛叔的react-native dvastarter 点击打开链接
我先说下两者的区别,
1,beta7版本,不允许嵌套跳转,请看场景:假设现在的路由栈是这样的:
const MainNavigator = StackNavigator( { HomeNavigator: {screen: HomeNavigator}, MyMemberShip: {screen: MyMemberShip},//我的推荐人 }, { headerMode: 'none', mode: 'modal', navigationOptions: { cardStack: { gesturesEnabled: false, }, }, } , );
HomeNavigator是一个TabNavigator,如果我想从MyMemberShip跳转到HomeNavigator中其中的一个tab页,直接navigate是做不到的,不可以嵌套跳转,如想做到需要这样做,我用的是redux的写法,其他写法自行修改:
This.props.dispatch(NavigationActions.navigate({routeName:’HomeNavigator’},action:[NavigationAction.navigate({routeName:’xxxTab’})])
其中xxxtab 是你要跳转tab页的名字
而beta11版本,还是刚才的场景,只需要navigate到某个tab页面即可,可以nested navigate;
2,监听跳转,beta7版本可以这样用,
render() { const {dispatch, router} = this.props const navigation = addNavigationHelpers({dispatch, state: router}) return ( <View style={{flex: 1}}> <AppNavigator navigation={navigation} onNavigationStateChange={(prevState, currentState) => { const currentScreen = getCurrentRouteName(currentState); const prevScreen = getCurrentRouteName(prevState); if (prevScreen == 'PayManager' && currentScreen == 'SubmitOrder') { //做自己的操作,如刷新页面 } }} /> </View> ) }
,
即,navigation可以作为props进行传递,同时也在redux中进行存储,beta11不允许,只能在相应的models里面做监听和其他操作,如tab页切换的时候刷新相应的界面,或者动态显示tabbar,
if(payload.type=='Navigation/NAVIGATE'&&payload.routeName=='WorkSpace') { payload.params = {tabBarVisible: false} payload.type='Navigation/SET_PARAMS' payload.key='WorkSpace' yield put({ type: 'apply', payload, }) }
3,back回退到任何界面,官方文档提供的方法是这样的:
也就是根据key来back,这里需要明白2个地方,第一是如果back({null}),即回退到上一级,第二是 如果现在的路由栈是 A-B-C-D,如果想从D回到A,需要拿到B的key,然后进行如下操作:
this.props.navigation.dispatch(Navigation.back({key:'KeyofB'}))
,明白了这两点,才能更好的进行back操作,
因为screen在初始化的时候key是一个随机数,所以我们需要通过总的路由栈拿到需要进行back操作的key,进而进行back操作,
如果navigation和redux进行绑定,可以在任意screen 拿到路由栈,进行如下操作:
function getCurrentScreens(navigationState) { if (!navigationState) { return null } const route = navigationState.routes[navigationState.index] if (route.routes) { return getCurrentScreens(route) } return navigationState.routes}此方法是找到当前的路由栈,因为app有可能存在多个路由栈嵌套,需要拿到当前页面所在的路由栈,接下来做自己的业务操作:
goBack(){ const nowRouters= getCurrentScreens(this.props.router) console.log(nowRouters) //goback const backAction = NavigationActions.back({ key: nowRouters[1].key //key根据自己的业务改变 }) this.props.dispatch(backAction) }
这样就可以做到 回退两级,三级,甚至多级,当然,你还可以根据这个逻辑,自己做个simgletone 模式,比如说在商品详情和购物车之间互跳多次,而我们只需要在路由栈中保留一次,也可以根据上面的方法,判断此screenName是否存在,存在back到这个界面,而不是navigate,抛砖引玉,
4,跳转卡顿,第一是跳转动画和网络请求冲突,解决办法,在navigate过去的界面进行如下操作,
componentDidMount() { //等待动画完成 InteractionManager.runAfterInteractions(() => { this.props.dispatch(createAction('info/detail')(this.props.navigation.state.contentId)) }) }
第二是navigation进行操作的时候会输出很多log,把他屏蔽掉会路由操作会流畅很多,尤其是android端,在最新版本(0.46)中已经默认不输出任何跳转log,在程序的入口进行如下操作:
if(!__DEV__){console.log = ()=>{},console.warn = ()=>{}} //是否为开发模式
5,再次点击tab重新加载页面,如新闻类的,再次点击tab重新加载数据
tabBarComponent: ({jumpToIndex, ...props, navigation}) => ( <TabBarBottom {...props} jumpToIndex={index => { const { state } = navigation, { routes } = state; if (state.index === index && routes[index].index !== 0) {navigation.dispatch(NavigationActions.reset({ index, key: routes[index].key, actions: [ NavigationActions.navigate({ routeName: routes[index].routeName }) ] }) } else { jumpToIndex(index); } ))/> )
6,tab页面弹出键盘,tabbar被顶到键盘上面,处理如下
componentWillMount() {this.keyboardDidShowListener = Keyboard.addListener('keyboardDidShow',this._keyboardDidShow.bind(this));this.keyboardDidHideListener = Keyboard.addListener('keyboardDidHide', this._keyboardDidHide.bind(this));}componentWillUnmount() {this.keyboardDidShowListener.remove();this.keyboardDidHideListener.remove();}_keyboardDidShow() {this.props.navigation.setParams({tabBar:{visible:false}})}_keyboardDidHide() {debugger;this.props.navigation.setParams({tabBar:{visible:true}})}
7,增加tabbar模式‘left‘和’right‘,即侧边栏,这个对于手机端影响不大,主要是pad端,文档中并没有提供,只能修改源码实现,代码如下
首先在node-modules目录下
复制TabBarBottom到当前目录,并更改style,
const styles = StyleSheet.create({ tabBar: { width:100, //根据个人需求更改宽度 height: '100%', borderRightWidth: StyleSheet.hairlineWidth, borderRightColor: 'rgba(0, 0, 0, .2)', backgroundColor: '#f4f4f4', // Default background color in iOS 10 },
tab的样式可以在这进行修改
tab: { flex: 1, flexDirection:'row', alignItems: 'center', // justifyContent: 'flex-start', },
第二步,在node_modules/react-native-tab-view/src/TabViewAnimated.js中的render方法修改如下:
render() { const { /* eslint-disable no-unused-vars */ navigationState, onRequestChangeTab, onChangePosition, canJumpToTab, lazy, initialLayout, renderScene, /* eslint-enable no-unused-vars */ renderPager, renderHeader, renderFooter, renderRight, //更改 renderLeft, //更改 ...rest } = this.props; const props = this._buildSceneRendererProps(); const isRow=renderRight||renderLeft return ( <View onLayout={this._handleLayout} loaded={this.state.loaded} style={[styles.container, this.props.style, {flexDirection:isRow?'row':'column'}]} //更改 > {/*更改*/} {!isRow&&renderHeader && <View collapsable={false}>{renderHeader(props)}</View>} {isRow&&renderLeft && <View collapsable={false}>{renderLeft(props)}</View>} {renderPager({ ...props, ...rest, children: navigationState.routes.map((route, index) => this._renderScene({ ...props, route, index, focused: index === navigationState.index, }), ), })} {!isRow&&renderFooter && <View collapsable={false}>{renderFooter(props)}</View>} {/*更改*/} {isRow&&renderRight && <View collapsable={false}>{renderRight(props)}</View>} </View> ); }
第三步,在node_modules/react-navigation/src/views/TabView/TabView.js 中
18行
export type TabViewConfig = { tabBarComponent?: ReactClass<*>, tabBarPosition?: 'top' | 'bottom'|'left'|'right', //更改 tabBarOptions?: {}, swipeEnabled?: boolean, animationEnabled?: boolean, lazy?: boolean,};34行
type Props = { tabBarComponent?: ReactClass<*>, tabBarPosition?: 'top' | 'bottom'|'left'|'right', tabBarOptions?: {}, swipeEnabled?: boolean, animationEnabled?: boolean, lazy?: boolean,
145行
let renderHeader; let renderFooter; let renderPager; let renderLeft; // let renderRight; // const { state } = this.props.navigation; const options = router.getScreenOptions( this.props.childNavigationProps[state.routes[state.index].key], screenProps || {} ); const tabBarVisible = options.tabBarVisible == null ? true : options.tabBarVisible; if (tabBarComponent !== undefined && tabBarVisible) { //更改 if (tabBarPosition === 'bottom') { renderFooter = this._renderTabBar; } else if (tabBarPosition === 'top'){ renderHeader = this._renderTabBar; }else if (tabBarPosition === 'left'){ renderLeft = this._renderTabBar; }else{ renderRight = this._renderTabBar; } }
以及177行:
const props = { lazy, animationEnabled, swipeEnabled, renderPager, renderHeader, renderFooter, renderLeft, // renderRight, // renderScene: this._renderScene, onRequestChangeTab: this._handlePageChanged, navigationState: this.props.navigation.state, screenProps: this.props.screenProps, style: styles.container, };
这样 在使用TabNavigator 的时候 可以正常使用了:
const HomeNavigator = TabNavigator( { Home: { screen: Home }, Account: { screen: Account }, }, { tabBarComponent: TabBarLeft, tabBarPosition: 'left', swipeEnabled: false, animationEnabled: false, lazyLoad: true, })
这个还是有宽高的问题,所以我自己fork了一下,需要的朋友可以私我
二,关于轮播图及图片压缩,
轮播图不管是swiper或者是viewpagerAndroid,在android端都会出现问题,需要我们做出相关操作,
如果是swiper加tabnavigator连用,会造成第一个tab页面图片不显示,beta11已经修复这个问题,说下在beta7版本的解决方案,代码如下
componentDidMount(){ this.timer= setTimeout(()=>{ this.setState({ visible:true }) },300) }
heaer=()=> { if(this.state.visible){ // console.log(this.props.scrollImages) return ( <Swiper height={200} index={0} autoplay={false}> {/*轮播图*/} {this.props.scrollImages.map((item, i) => <TouchableWithoutFeedback key={i} onPress={() => { this.thumbPressHandle(i) }}> <FastImage style={styles.sImage} source={{uri: IMG_URL + item.resUrl}}/> </TouchableWithoutFeedback>)} </Swiper> )}else{ return(<View style={{flex:1}}/>) } },另外,如果在安卓端遇到轮播图需要点击以后图片才会加载的情况,把swiper的
removeClippedSubviews 属性设置为false
按上述操作即可解决,图片压缩,建议使用这个库,
https://github.com/DylanVann/react-native-fast-image
使用简单,效果显著,推荐使用,
每天学习,码代码很累吧 ,加下群互相交流下咯 新建QQ群:657950514,不能说问及必答,只能说知无不言
- react-navigation及dva使用(三)
- react-navigation使用及dva初探一
- react-navigation使用及dva初探二
- react-navigation Navigation使用
- 基于react+redux的轻量级框架dva初使用及应用逻辑分析
- react-navigation 简单使用
- react-navigation使用
- react-navigation使用技巧
- react-navigation使用
- react-navigation使用心得
- React Navigation基础使用
- react-navigation使用技巧
- react-navigation 使用详解
- react-navigation使用技巧
- react-navigation使用技巧
- react-navigation的使用
- react-navigation 使用详解
- react-navigation使用技巧
- CodeVS 1018 单词接龙 题解
- tar: Removing leading '/' from member names
- 【链表】判断两个链表是否相交,并求出交点
- 字符设备驱动基础篇5——驱动如何操控硬件(动静态映射操作LED)
- 深入理解Java之线程池
- react-navigation及dva使用(三)
- 新起点,从黑马JavaEE开始
- Win10安装PostgreSQL数据库遇到的问题总结
- 数据库中间件 MyCAT源码分析 —— 跨库两表Join
- 51nod1366(43/600)
- JavaWeb中Ajax的使用-基本使用+省市联动例子
- 数据库中间件 MyCAT源码分析 —— XA分布式事务
- spring boot中controller注意事项
- Maven Assembly插件简单介绍