React Native 动态权限路由导航(react-navigation)配置
1,实现背景
项目中可能会遇到权限路由配置的需求,根据不同账户权限,去动态的进行导航路由的显隐,以及不同的机型适配,那么我们就需要进行基于后端权限动态的生成相关路由配置。
2,实现思路
其实实现动态路由就是把不同类型的(StackNavigator,TabNavigator,DrawerNavigator)导航,动态的配置它们的RoutConfigs,NavigatorConfig属性。前者配置组件路由,后者配置导航样式属性等。
用过react-navigation的小伙伴应该知道一般的RoutConfigs都是写死的静态配置。但这种静态配置无法像更改navigatorConfig那样通过页面静态配置,动态配置去改变,那么我们就只能在创建相关类型的路由实例之前去动态的更改RoutConfigs以进行动态权限配置。
3,实现细节
登录成功–访问权限接口–基于权限配置RouConfigs
*注意: 使用hooks useEffect监听AppNavigatorRefresh属性,每次新用户登录时进行触发,然后重新创建AppContainer,进行路由导航重新渲染。global:为node全局属性declare var global: typeof globalThis;
登录
actions.userLogin(body, {
resolved: (res) => {
// something
// 登录成功后进行权限初始化
global.tabNavigatoeRefresh().then(() => {
// 初始化完成后再进行登录成功页面初始化跳转
const resetActions = StackActions.reset({
index: 0,
actions: [NavigationActions.navigate({ routeName: 'Main' })],
});
this.props.navigation.dispatch(resetActions);
});
},
rejected: (msg) => {
this.props.actions.loading(false);
actions.toast(msg);
},
});
访问权限接口
// 用户切换时权限菜单初始化回调函数
global.tabNavigatoeRefresh = () => {
return new Promise((resolve, reject) => {
const { AppNavigatorRefresh } = this.state;
userService.getPermission({ lan: i18n.locale }).then(
(res) => {
this.setState({
AppNavigatorRefresh: !AppNavigatorRefresh,
PermissionArray: res?.data,
});
resolve();
},
() => {
// 接口调用异常时不基于权限初始化,使用静态默认Roufings
this.setState({
AppNavigatorRefresh: !AppNavigatorRefresh,
PermissionArray: null,
});
resolve();
}
);
});
};
render() {
const { refresh, drawerView, unReadMsgCount, AppNavigatorRefresh, PermissionArray } = this.state;
return (
<AppForNavigator
refresh={refresh}
PermissionArray={PermissionArray}
unReadMsgCount={unReadMsgCount}
AppNavigatorRefresh={AppNavigatorRefresh}
/>
)
}
基于权限配置RouConfigs
const AppForNavigator = (props) => {
const { PermissionArray, AppNavigatorRefresh } = props;
useEffect(() => {
if (PermissionArray) {
// 基于账户权限进行权限动态配置,重新创建新的AppContainer
// 将MainHome路由导航配置抽离成动态可配置变量
if (!PermissionArray?.some((e) => e?.permission === 'overview.view')) {
navigatorConfigs.Main = MainHome({ isDelete: true });
} else {
navigatorConfigs.Main = MainHome({ isDelete: false });
}
AppContainer = createAppContainer(
createStackNavigator(navigatorConfigs, {
defaultNavigationOptions: ({ navigation }) =>
StackOptions({
navigation,
}),
})
);
// 创建之后进行AppContainer刷新
global.refresh();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [AppNavigatorRefresh]);
return (
<AppContainer
ref={(navigatorRef) => {
NavigationService.setTopLevelNavigator(navigatorRef);
}}
screenProps={{
refresh: props.refresh,
unReadMsgCount: props.unReadMsgCount === 0 ? null : props.unReadMsgCount,
}}
/>
);
};
export default AppForNavigator;