React-admin v2升级v3遇权限空、上下文不一致问题求助
问题1:permissions始终为undefined,但authProvider.getPermissions()返回有效值
这个问题主要源于react-admin v3对权限组件的行为和初始化逻辑的调整:
<WithPermissions>组件的参数结构变更
在v3中,<WithPermissions>的render回调函数返回的对象新增了isLoading状态字段——哪怕你的authProvider.getPermissions()是同步返回结果,v3内部也会通过异步流程处理权限初始化。如果不先判断加载状态就直接渲染,就会出现permissions为undefined的情况。你需要先等待权限加载完成,再渲染后续内容:
<WithPermissions render={({ permissions, isLoading }) => { if (isLoading) return <div>Loading permissions...</div>; return ( <AppContextProvider permissions={permissions} references={references} > <Layout {...props} /> </AppContextProvider> ); }} />权限获取逻辑的优先级调整
v3中,connect高阶组件的执行时机可能早于权限数据的初始化。如果你用connect包裹了包含<WithPermissions>的组件,可能会导致组件在权限数据还未写入Redux store时就完成渲染。建议改用v3推荐的Hook方式获取权限,比如usePermissions,替代<WithPermissions>组件:const ComponentLayout = ({ references, ...props }) => { const { permissions, isLoading } = usePermissions(); if (isLoading) return <div>Loading permissions...</div>; return ( <AppContextProvider permissions={permissions} references={references} > <Layout {...props} /> </AppContextProvider> ); };
问题2:references传递给AppContextProvider时非空,但读取时为空对象
这个问题大概率和react-admin v3的Redux state结构变更以及上下文传递的时机有关:
Redux state中资源数据的访问路径变更
v3对state.admin.resources的结构做了调整:v2中资源的元数据直接存储在state.admin.resources[resourceName]下,但v3中,资源的配置信息被移到了state.admin.resources[resourceName].config中。如果你的mapStateToProps还是按v2的方式读取,可能会导致references的结构不符合预期。可以先打印
state.admin.resources确认结构,调整mapStateToProps:const mapStateToProps = (state) => { const references = {}; Object.keys(state.admin.resources).forEach((name) => { const resourceConfig = state.admin.resources[name].config; set(references, `${camelizePath(resourceConfig.name)}.name`, resourceConfig.name); }); return { references }; };上下文传递的时机与组件层级问题
v3中,Admin组件内部的上下文初始化时机晚于composeLayout返回的组件渲染时机。如果读取上下文的组件在AppContextProvider完成赋值前就渲染,就会读取到空对象。建议读取上下文的组件使用
useContextHook,并先确认数据存在后再使用:// 读取上下文的组件示例 const MyComponent = () => { const { references } = useContext(AppContext); if (!Object.keys(references).length) return null; // 等待数据加载完成 // 后续业务逻辑 };
额外建议:v3中动态生成页面的最佳实践
在v3中,官方推荐使用useResourceDefinitions Hook来获取所有注册的资源,替代直接从Redux state读取,这样更符合v3的API设计,也能避免state结构变更带来的问题:
import { useResourceDefinitions, usePermissions } from 'react-admin'; const ComponentLayout = ({ ...props }) => { const { permissions, isLoading } = usePermissions(); const resources = useResourceDefinitions(); const references = {}; Object.keys(resources).forEach((name) => { set(references, `${camelizePath(name)}.name`, name); }); if (isLoading) return <div>Loading...</div>; return ( <AppContextProvider permissions={permissions} references={references} > <Layout {...props} /> </AppContextProvider> ); }; // 无需再用connect,直接返回组件即可
内容的提问来源于stack exchange,提问作者Dimitri Kopriwa

