关于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’})])
而beta11版本,还是刚才的场景,只需要navigate到某个tab页面即可,可以nested navigate;
2,监听跳转,beta7版本可以这样用,
render() {
const {dispatch, router} = this.props
const navigation = addNavigationHelpers({dispatch, state: router})
return (
{
const currentScreen = getCurrentRouteName(currentState);
const prevScreen = getCurrentRouteName(prevState);
if (prevScreen == 'PayManager' && currentScreen == 'SubmitOrder') {
//做自己的操作,如刷新页面
}
}}
/>
)
}
即,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'}))
因为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)
}
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}) => (
{ 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}})
}
首先在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',
},
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 (
{/*更改*/}
{!isRow&&renderHeader && {renderHeader(props)} }
{isRow&&renderLeft && {renderLeft(props)} }
{renderPager({
...props,
...rest,
children: navigationState.routes.map((route, index) =>
this._renderScene({
...props,
route,
index,
focused: index === navigationState.index,
}),
),
})}
{!isRow&&renderFooter && {renderFooter(props)} }
{/*更改*/}
{isRow&&renderRight && {renderRight(props)} }
);
}
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,
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,
};
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 (
{/*轮播图*/}
{this.props.scrollImages.map((item, i) => {
this.thumbPressHandle(i)
}}>
)}
)}else{
return( )
}
}
,另外,如果在安卓端遇到轮播图需要点击以后图片才会加载的情况,把swiper的
removeClippedSubviews 属性设置为false
按上述操作即可解决,图片压缩,建议使用这个库,
https://github.com/DylanVann/react-native-fast-image
使用简单,效果显著,推荐使用,
每天学习,码代码很累吧 ,加下群互相交流下咯 新建QQ群:657950514,不能说问及必答,只能说知无不言