React-Native如何做页面权限过滤

2,871 阅读2分钟

前言

react-navigation 内部并没有beforeEnterrouterWillLeave这样的钩子函数, 这使得我们做页面的拦截控制变得相对复杂,

所幸,在官方看到了提供的自定义路由

其中getStateForAction和getStateForRouteNamesChange两个方法吸引了我们的注意力,一起来看下

getStateForAction

我们先看方法的声明

方法一共有两个参数,分别是action,state,经过一番源码的查找,简单整理如下

  • 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

并没有在源码中找到该方法,欢迎对这个方法有研究的大佬在评论区补充

需要注意的地方

  1. 在方法内部不要直接修改形参,也不要浅拷贝。因为此处的state为引用类型,state在传递的时候只是传递了地址, 若是修改了形参的值,state在内存中的值就被改变了,从而影响react-navigation内部其他 函数的运行,所以这里要深拷贝一层来操作。

  2. 本文只是对一个Navigation栈内的页面进行拦截,如果使用了栈的嵌套,则需要使用递归或者单独对某个栈进行拦截