You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Admin结合Firestore实现基于权限动态渲染Resource的问题求助

解决方案:正确结合AdminUI与权限控制,避免未登录时渲染资源

我明白你的问题所在:当你把AdminUI放在AsyncResources内部时,未登录状态下AsyncResources会先执行usePermissions,此时permissions为null,导致后续代码崩溃;而把AdminUI放在外层时,又遇到了资源不能被包裹的限制。以下是一个可行的解决方案,既能利用AdminUI的内置认证重定向,又能根据权限动态渲染资源:

核心思路

  1. 让AdminUI作为AdminContext的直接子组件,利用它的内置认证逻辑处理未登录重定向。
  2. 在AdminUI内部添加一个条件渲染组件,负责处理权限加载、资源动态生成的逻辑,用Fragment包裹多个资源(React Admin允许这种方式,因为Fragment不会生成额外DOM节点)。
  3. 确保Firestore数据请求仅在用户已认证且权限加载完成后执行,避免未授权调用。

完整代码示例

import { AdminContext, AdminUI, usePermissions, useAuthState } from 'react-admin';
import { useState, useEffect, Fragment } from 'react';
import firebase from 'firebase/app';
import 'firebase/firestore';

// 自定义加载组件、布局、主题等
import Loading from './Loading';
import CustomLayout from './CustomLayout';
import theme from './theme';
import RequestList from './RequestList';
import RequestEdit from './RequestEdit';
import ExpertList from './ExpertList';
import authProvider from './authProvider';
import dataProvider from './dataProvider';

function App() {
  return (
    <AdminContext authProvider={authProvider} dataProvider={dataProvider}>
      <AdminUI layout={CustomLayout} theme={theme}>
        <ConditionalResources />
      </AdminUI>
    </AdminContext>
  );
}

function ConditionalResources() {
  const [emails, setEmails] = useState<string[]>([]);
  const { loading, permissions } = usePermissions();
  const { isAuthenticated } = useAuthState();

  // 仅在用户已认证且权限可用时获取Firestore数据
  useEffect(() => {
    const fetchExperts = async () => {
      if (!isAuthenticated || !permissions) return;
      
      const expertsSnapshot = await firebase.firestore().collection("experts").get();
      const docIds = expertsSnapshot.docs.map(doc => doc.id);
      setEmails(docIds);
    };

    fetchExperts();
  }, [isAuthenticated, permissions]);

  // 权限加载中,显示加载状态
  if (loading) {
    return <Loading loadingPrimary="WePractice Admin UI" loadingSecondary="Loading..." />;
  }

  // 未登录或权限未就绪,返回null(此时AdminUI会触发登录重定向)
  if (!isAuthenticated || !permissions) {
    return null;
  }

  // 管理员权限:渲染所有专家请求和专家列表
  if (permissions.admin) {
    return (
      <Fragment>
        {emails.map(email => (
          <Resource
            key={email}
            options={{ label: email }}
            name={`experts/${email}/requests`}
            list={RequestList}
            edit={RequestEdit}
          />
        ))}
        <Resource name="experts" list={ExpertList} />
      </Fragment>
    );
  }

  // 普通用户:渲染自己的请求列表
  return (
    <Resource
      options={{ label: permissions.email }}
      name={`experts/${permissions.email}/requests`}
      list={RequestList}
      edit={RequestEdit}
    />
  );
}

export default App;

关键说明

  • 认证流程:AdminUI会自动调用authProvider的checkAuth方法,未登录时直接重定向到登录页,此时ConditionalResources不会被渲染,避免了permissions为null的崩溃问题。
  • 条件渲染:在权限加载完成前,返回加载组件;未登录时返回null,确保不会触发资源渲染逻辑。
  • 资源包裹:用Fragment(<>简写)包裹多个Resource组件,既满足React的单元素返回要求,又不会被React Admin视为无效包裹(因为Fragment不生成实际DOM节点)。
  • Firestore请求时机:将Firestore数据请求的触发条件绑定到isAuthenticated和permissions,确保只有授权用户才能访问Firestore数据,同时避免未登录时的无效请求。

确保你的authProvider正确实现了checkAuth方法,示例如下(供参考):

const authProvider = {
  checkAuth: () => {
    const user = firebase.auth().currentUser;
    return user ? Promise.resolve() : Promise.reject();
  },
  // 其他authProvider方法(login, logout, getPermissions等)
};

内容的提问来源于stack exchange,提问作者Pietro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 23:37:48