您好,登錄后才能下訂單哦!
這篇文章主要講解了“react-router v6怎么實現動態路由”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“react-router v6怎么實現動態路由”吧!
大致思路就是:先只在路由表配置默認路由,例如登錄頁面,404頁面。再等待用戶登錄成功后,獲取到用戶權限列表和導航列表,寫一個工具函數遞歸調用得出路由表,在根據關鍵字映射成組件,最后返回得到新的路由表。
流程如下
用戶登錄成功
獲取用戶權限列表
獲取用戶導航菜單列表
根據權限和導航生成路由表
import { lazy } from "react"; import { Navigate } from "react-router-dom"; // React 組件懶加載 // 快速導入工具函數 const lazyLoad = (moduleName: string) => { const Module = lazy(() => import(`views/${moduleName}`)); return <Module />; }; // 路由鑒權組件 const Appraisal = ({ children }: any) => { const token = localStorage.getItem("token"); return token ? children : <Navigate to="/login" />; }; interface Router { name?: string; path: string; children?: Array<Router>; element: any; } const routes: Array<Router> = [ { path: "/login", element: lazyLoad("login"), }, { path: "/", element: <Appraisal>{lazyLoad("sand-box")}</Appraisal>, children: [ { path: "", element: <Navigate to="home" />, }, { path: "*", element: lazyLoad("sand-box/nopermission"), }, ], }, { path: "*", element: lazyLoad("not-found"), }, ]; export default routes;
注意帶 //import! 的標識每次導航列表更新時,再觸發路由更新action
handelFilterRouter 就是根據導航菜單列表 和權限列表 得出路由表的
import { INITSIDEMENUS, UPDATUSERS, LOGINOUT, UPDATROUTES } from "./contant"; import { getSideMenus } from "services/home"; import { loginUser } from "services/login"; import { patchRights } from "services/right-list"; import { handleSideMenu } from "@/utils/devUtils"; import { handelFilterRouter } from "@/utils/routersFilter"; import { message } from "antd"; // 獲取導航菜單列表 export const getSideMenusAction = (): any => { return (dispatch: any, state: any) => { getSideMenus().then((res: any) => { const rights = state().login.users.role.rights; const newMenus = handleSideMenu(res, rights); dispatch({ type: INITSIDEMENUS, menus: newMenus }); dispatch(updateRoutesAction()); //import! }); }; }; // 退出登錄 export const loginOutAction = (): any => ({ type: LOGINOUT }); // 更新導航菜單 export const updateMenusAction = (item: any): any => { return (dispatch: any) => { patchRights(item).then((res: any) => { dispatch(getSideMenusAction()); }); }; }; // 路由更新 //import! export const updateRoutesAction = (): any => { return (dispatch: any, state: any) => { const rights = state().login.users.role.rights; const menus = state().login.menus; const routes = handelFilterRouter(rights, menus); //import! dispatch({ type: UPDATROUTES, routes }); }; }; // 登錄 export const loginUserAction = (item: any, navigate: any): any => { return (dispatch: any) => { loginUser(item).then((res: any) => { if (res.length === 0) { message.error("用戶名或密碼錯誤"); } else { localStorage.setItem("token", res[0].username); dispatch({ type: UPDATUSERS, users: res[0] }); dispatch(getSideMenusAction()); navigate("/home"); } }); }; };
說一說我這里為什么要映射element 成對應組件這部操作,原因是我使用了redux-persist(redux持久化), 不熟悉這個插件的可以看看我這篇文章:redux-persist若是直接轉換后存入本地再取出來渲染是會有問題的,所以需要先將element保存成映射路徑,然后渲染前再進行一次路徑映射出對應組件。
每個后臺的數據返回格式都不一樣,需要自己去轉換,我這里的轉換僅供參考。ps:defaulyRoutes和默認router/index.ts導出是一樣的,可以做個小優化,復用起來。
import { lazy } from "react"; import { Navigate } from "react-router-dom"; // 快速導入工具函數 const lazyLoad = (moduleName: string) => { const Module = lazy(() => import(`views/${moduleName}`)); return <Module />; }; const Appraisal = ({ children }: any) => { const token = localStorage.getItem("token"); return token ? children : <Navigate to="/login" />; }; const defaulyRoutes: any = [ { path: "/login", element: lazyLoad("login"), }, { path: "/", element: <Appraisal>{lazyLoad("sand-box")}</Appraisal>, children: [ { path: "", element: <Navigate to="home" />, }, { path: "*", element: lazyLoad("sand-box/nopermission"), }, ], }, { path: "*", element: lazyLoad("not-found"), }, ]; // 權限列表 和 導航菜單 得出路由表 element暫用字符串表示 后面渲染前再映射 export const handelFilterRouter = ( rights: any, menus: any, routes: any = [] ) => { for (const menu of menus) { if (menu.pagepermisson) { let index = rights.findIndex((item: any) => item === menu.key) + 1; if (!menu.children) { if (index) { const obj = { path: menu.key, element: `sand-box${menu.key}`, }; routes.push(obj); } } else { handelFilterRouter(rights, menu.children, routes); } } } return routes; }; // 返回最終路由表 export const handelEnd = (routes: any) => { defaulyRoutes[1].children = [...routes, ...defaulyRoutes[1].children]; return defaulyRoutes; }; // 映射element 成對應組件 export const handelFilterElement = (routes: any) => { return routes.map((route: any) => { route.element = lazyLoad(route.element); return route; }); };
import routes from "./router"; import { useRoutes } from "react-router-dom"; import { shallowEqual, useSelector } from "react-redux"; import { useState, useEffect } from "react"; import { handelFilterElement, handelEnd } from "@/utils/routersFilter"; import { deepCopy } from "@/utils/devUtils"; function App() { console.log("first"); const [rout, setrout] = useState(routes); const { routs } = useSelector( (state: any) => ({ routs: state.login.routes }), shallowEqual ); const element = useRoutes(rout); // 監聽路由表改變重新渲染 useEffect(() => { // deepCopy 深拷貝state數據 不能影響到store里的數據! // handelFilterElement 映射對應組件 // handelEnd 將路由表嵌入默認路由表得到完整路由表 const end = handelEnd(handelFilterElement(deepCopy(routs))); setrout(end); }, [routs]); return <div className="height-all">{element}</div>; } export default App;
感謝各位的閱讀,以上就是“react-router v6怎么實現動態路由”的內容了,經過本文的學習后,相信大家對react-router v6怎么實現動態路由這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。