Skip to content
This repository has been archived by the owner on Jun 20, 2024. It is now read-only.

Easy to use permission management based on react-router v6

Notifications You must be signed in to change notification settings

linxianxi/react-router-auth-plus

Repository files navigation

react-router-auth-plus

Introduce

Make you easy to use permission management based on react-router v6.

Install

npm install react-router-auth-plus

OR

yarn add react-router-auth-plus

Usage

if user auth is ["auth1"], home router auth configure ["auth1", "auth2"], will be judged as having permission.

How to use

// auth: string | string[]
const routers = [{ path: "/home", element: <Home />, auth: ["admin"] }];

Configure the routes

// routers.tsx
import { lazy } from "react";
import { Navigate } from "react-router-dom";
import { AuthRouteObject } from "react-router-auth-plus";

const Layout = lazy(() => import("./layout/Layout"));
const Application = lazy(() => import("./pages/Application"));
const Home = lazy(() => import("./pages/Home"));
const Login = lazy(() => import("./pages/Login"));
const NotFound = lazy(() => import("./pages/404"));
const Setting = lazy(() => import("./pages/Setting"));

export const routers: AuthRouteObject[] = [
  {
    path: "/",
    element: <Layout />,
    // it will pass th routers prop to Layout
    // genRoutersProp: true,
    // it will pass the authRouters prop to Layout, you can use it to generate menus
    genAuthRoutersProp: true,
    children: [
      {
        element: <Home />,
        auth: ["admin"],
        index: true,
      },
      {
        path: "/setting",
        element: <Setting />,
      },
      {
        path: "/application",
        element: <Application />,
        auth: ["application"],
      },
    ],
  },
  {
    path: "/login",
    element: <Login />,
  },
  { path: "*", element: <NotFound /> },
];

In react-router-dom 6.4+, you can choose two ways to render routers

1、you can use RouterProvider and createBrowserRouter

// App.tsx
import NotAuth from "./pages/403";
import Loading from "./components/Loading";
import { getAuthRouters } from "react-router-auth-plus";
import useSWR from "swr";
import { createBrowserRouter, RouterProvider } from "react-router-dom";
import { routers } from "./routers";
import { Router } from "@remix-run/router";
import { Suspense, useMemo } from "react";

// if you want to use router navigate outside react component
export let router: Router;

const fetcher = async (url: string): Promise<string[]> =>
  await new Promise((resolve) => {
    setTimeout(() => {
      resolve(["admin"]);
    }, 1000);
  });

function App() {
  const { data: auth, isValidating } = useSWR("/api/user", fetcher, {
    // close fetch on window focus
    revalidateOnFocus: false,
  });

  const _routers = useMemo(() => {
    const result = getAuthRouters({
      routers,
      noAuthElement: (router) => <NotAuth />,
      render: (element) => (isValidating ? <Loading /> : element),
      auth: auth || [],
    });

    router = result;

    return result;
  }, [auth]);

  return (
    <Suspense fallback={<Loading />}>
      <RouterProvider
        router={createBrowserRouter(_routers)}
        // route loader loading
        fallbackElement={<Loading />}
      />
    </Suspense>
  );
}

export default App;

2、you can use BrowserRouter

import NotAuth from "./pages/403";
import Loading from "./components/Loading";
import { getAuthRouters } from "react-router-auth-plus";
import useSWR from "swr";
import { useRoutes } from "react-router-dom";
import { routers } from "./routers";

const fetcher = async (url: string): Promise<string[]> =>
  await new Promise((resolve) => {
    setTimeout(() => {
      resolve(["admin"]);
    }, 1000);
  });

function App() {
  const { data: auth, isValidating } = useSWR("/api/user", fetcher, {
    // close fetch on window focus
    revalidateOnFocus: false,
  });

  return useRoutes(
    getAuthRouters({
      routers,
      noAuthElement: (router) => <NotAuth />,
      render: (element) => (isValidating ? <Loading /> : element),
      auth: auth || [],
    })
  );
}

export default App;
// main.tsx(vite) or index.tsx(create-react-app)
ReactDOM.createRoot(document.getElementById("root") as HTMLElement).render(
  <BrowserRouter>
    <App />
  </BrowserRouter>
);

Dynamic Menus

If you set genRoutersProp and genAuthRoutersProp in router config, react-router-auth-plus automatically passes routers and authRouters to props.

// Layout.tsx
import { FC } from "react";
import { AuthRouteObject } from "react-router-auth-plus";

interface LayoutProps {
  // children routers (if you set genRoutersProp)
  routers?: AuthRouteObject[];
  // children auth routers (if you set genAuthRoutersProp)
  authRouters?: AuthRouteObject[];
}

const Layout:FC<LayoutProps> = ({ routers = [], authRouters = [] }) => {
   // you can use this to generate your menus
   console.log("authRouters", authRouters);
   return ...
}

If you want to config menu name and icon in the routes

// routers.tsx
type MetaMenu = {
  name?: string,
  icon?: React.ReactNode,
};

export type MetaMenuAuthRouteObject = AuthRouteObject<MetaMenu>;

export const routers: MetaMenuAuthRouteObject[] = [
  {
    path: "/",
    element: <Layout />,
    genAuthRoutersProp: true,
    children: [
      {
        element: <Home />,
        auth: ["admin"],
        index: true,
        name: "home",
        icon: <HomeOutlined />,
      },
      {
        path: "/setting",
        element: <Setting />,
      },
      {
        path: "/application",
        element: <Application />,
        auth: ["application"],
      },
    ],
  },
  {
    path: "/login",
    element: <Login />,
  },
  { path: "*", element: <NotFound /> },
];
// Layout.tsx
import { FC } from "react";
import { Outlet } from "react-router-dom";
import { MetaMenuAuthRouteObject } from "../routers";

interface LayoutProps {
  authRouters?: MetaMenuAuthRouteObject[];
}

const Layout: FC<LayoutProps> = ({ authRouters = [] }) => {
  // you can get name and icon
  console.log("authRouters", authRouters);
  return ...;
};

export default Layout;

API

getAuthRouters

Property Description Type Required
auth permissions of the current user string[] true
noAuthElement the element that is displayed when has no permissions (router: AuthRouteObject) => ReactNode false
render custom render page (element: ReactElement | null) => ReactElement | null false
routers all routers AuthRouteObject[] true

About

Easy to use permission management based on react-router v6

Resources

Stars

Watchers

Forks

Packages

No packages published