前言
react-navigation 内部并没有beforeEnter、 routerWillLeave这样的钩子函数, 这使得我们做页面的拦截控制变得相对复杂,
所幸,在官方看到了提供的自定义路由
getStateForAction
我们先看方法的声明
- action 当前的一次用户操作 比如NAVIGATE或者REPLACE
- state 当前navigation栈的所有信息
然后debug看一下具体的结构,
从debug信息中可以看到,action就是我们每次调用navigate方法的参数
// 调用navigate方法
this.props.navigation.navigate('InfoChart', {
city_id: "balabalabalabala"
});
state是当前navigation栈的所有信息
官网没看到中文的翻译,这里只能看英文了,主要意思是:
接受当前的state和action,action内部有routename和routeParamList,经过处理后返回一个新state。
也就是说,state经过改变后,return出来,react-navigation就可以实现页面跳转了。
跳转的思路有了,那如何判断用户从哪个页面进入呢,
上面已经说了,action内部有routename
有了页面来源,也有了页面拦截方法,接下来去实现
index.js
+ import Filter from './Filter';
// 创建路由栈
const AppStack = createStackNavigator(routeConfigMap, stackConfig);
+ // 拦截路由栈内页面的跳转
+ AppStack.router.getStateForAction = Filter(AppStack);
filter.js
export default function Filter(stack) {
// 1.首先保存栈的实例方法,用于页面放行
const NAVIGATE = stack.router.getStateForAction;
// 2.我们拦截所有用户相关页面,没有登录的话,让他们自己前往登录页面
if (['Check', 'Pay', 'Receipt'].includes(action.routeName)) {
const token = utils.getToken();
// 拦截到没有登录的用户
if(!token) {
// 3.这里注意不要直接去修改形参state,我们深拷贝一个对象来操作
const res = JSON.parse(JSON.stringify(state));
res.routes.push({
key: routeKey,
routeName: 'Login',
});
res.index = res.routes.length - 1;
return res;
}
}
}
// 最后在模拟器或真机测试即可
getStateForRouteNamesChange
并没有在源码中找到该方法,欢迎对这个方法有研究的大佬在评论区补充
需要注意的地方
-
在方法内部不要直接修改形参,也不要浅拷贝。因为此处的state为引用类型,state在传递的时候只是传递了地址, 若是修改了形参的值,state在内存中的值就被改变了,从而影响react-navigation内部其他 函数的运行,所以这里要深拷贝一层来操作。
-
本文只是对一个Navigation栈内的页面进行拦截,如果使用了栈的嵌套,则需要使用递归或者单独对某个栈进行拦截