瀏覽代碼

react day6:页面访问鉴权-1

daxia 2 年之前
父節點
當前提交
43afd40342

+ 172 - 0
20_React.js_VIP22/React路由.md

@@ -286,7 +286,179 @@ navigate({pathname: '/login'}, {replace: true, state: {}})
 
 ## 7. 页面访问权限
 
+> Vue Router中可以通过导航守卫钩子来拦截到所有的页面导航,根据当前用户权限决定是否继续导航。
+>
+> 但是React Router需要根据不同的路由定义方式来自行实现。
+
+### 7.1 自定义hook
+
+```js
+/**
+ *! 自定义hook
+ ** 1 hook 函数的名称 必须 以 'use'开头去命名
+ ** 2 自定义hook中可以任意使用内置的所有hook函数
+ */
+
+import { useEffect } from 'react';
+import { useLocation, useNavigate } from 'react-router-dom';
+const whiteList = ['/', '/about', '/login'];
+
+export function useAuth() {
+  let location = useLocation();
+  let navigate = useNavigate();
+  let token = localStorage.getItem('token');
+
+  useEffect(() => {
+    if (!token && !whiteList.includes(location.pathname)) {
+      navigate(`/login?from=${location.pathname}`);
+    }
+  }, [location]);
+}
+```
+
+### 7.2 Router Provider实现
+
+```jsx
+import { useNavigate } from 'react-router-dom';
+import { useAuth } from '../hooks/useAuth';
+
+export default function Protected() {
+  const navigate = useNavigate();
+  // 页面访问鉴权
+  useAuth();
+
+  return (
+    <div className="Protected">
+      <h3>受保护页面——需要登录后才可以访问</h3>
+      <div>
+        <button
+          onClick={() => {
+            if (window.confirm('确定退出系统吗')) {
+              localStorage.clear();
+              navigate('/login');
+            }
+          }}
+        >
+          退出登录
+        </button>
+      </div>
+    </div>
+  );
+}
+
+```
+
+
+
 ## 8. 其他
 
+### 8.1 路由懒加载
+
+> 为了提高React项目首次加载速度,推荐使用路由懒加载。
+
+实现时,需要从React核心库中引入`lazy`函数和`Suspense`组件。像这样,
+
+```jsx
+import { createBrowserRouter } from 'react-router-dom';
+import Home from '../pages/Home';
+import { lazy, Suspense } from 'react';
+
+const About = lazy(() => import('../pages/About'));
+
+const router = createBrowserRouter([
+  { path: '/', Component: Home },
+  {
+    path: '/about',
+    element: (
+      <Suspense fallback={<h3>加载中...</h3>}>
+        <About />
+      </Suspense>
+    ),
+  },
+]);
+
+export default router;
+```
+
+在定义路由时,React Router还提供了一系列组件:
+
+```jsx
+import './App.css';
+import { NavLink, Routes, Route } from 'react-router-dom';
+import { lazy, Suspense } from 'react';
+import Home from './pages/Home';
+
+// import About from './pages/About';
+// import User from './pages/User';
+import UserProfile from './pages/UserProfle';
+import UserPost from './pages/UserPost';
+
+const About = lazy(async () => {
+  await new Promise((resolve) => {
+    setTimeout(() => {
+      resolve();
+    }, 1000);
+  });
+  return import('./pages/About.jsx');
+});
+
+const User = lazy(() => import('./pages/User'));
+
+// 实现路由懒加载的高阶组件
+function withSuspense(Component) {
+  return (
+    <Suspense fallback={<h3>组件疯狂加载中...</h3>}>
+      <Component />
+    </Suspense>
+  );
+}
+
+function App() {
+  return (
+    <div className="App">
+      <header className="App-header">
+        <NavLink className="App-link" to={'/'}>
+          主页
+        </NavLink>{' '}
+        <NavLink className="App-link" to={'/about'}>
+          关于
+        </NavLink>
+        <NavLink className="App-link" to={'/user'}>
+          用户
+        </NavLink>
+      </header>
+      <main>
+        <Routes>
+          <Route path="/" element={<Home />} />
+          <Route path="/about" element={withSuspense(About)} />
+          <Route path="/user" element={withSuspense(User)}>
+            <Route index />
+            <Route path="profile" element={<UserProfile />} />
+            <Route
+              path="post"
+              // 并不会起作用。它只能在RouterProvider API中使用
+              lazy={() => import('./pages/UserPost.jsx')}
+              element={<UserPost />}
+            />
+          </Route>
+          <Route path="/list/:lid" />
+        </Routes>
+      </main>
+    </div>
+  );
+}
+
+export default App;
+```
+
+其中,`Route`组件就是定义路由的。当其path属性和当前地址匹配成功后,就会在其位置下渲染element绑定的React元素。
+
+同时可以定义多个`Route`组件,这样就可以在页面中定义多个路由。并且这些`Route`组件必须作为`Routes`组件的直接子代元素。
+
+为了将路由功能注入到项目中,需要在App组件中将整个项目代码包裹在一个`BrowserRouter`或者`HashRouter`组件中。
+
+- BrowserRouter 会实现一个基于History 模式的路由
+- HashRouter 会实现一个基于hash 模式的路由
+
 
 

+ 22 - 0
20_React.js_VIP22/day-6/code/react-router-lazy/src/hooks/useAuth.js

@@ -0,0 +1,22 @@
+/**
+ *! 自定义hook
+ ** 1 hook 函数的名称 必须 以 'use'开头去命名
+ ** 2 自定义hook中可以任意使用内置的所有hook函数
+ */
+
+import { useEffect } from 'react';
+import { useLocation, useNavigate } from 'react-router-dom';
+const whiteList = ['/', '/about', '/login'];
+
+export function useAuth() {
+  let location = useLocation();
+  let navigate = useNavigate();
+  let token = localStorage.getItem('token');
+
+  useEffect(() => {
+    // 如果用户既没有登录 同时访问的也不是白名单页面
+    if (!token && !whiteList.includes(location.pathname)) {
+      navigate(`/login?from=${location.pathname}`);
+    }
+  }, [location]);
+}

+ 21 - 0
20_React.js_VIP22/day-6/code/react-router-lazy/src/pages/Login.jsx

@@ -0,0 +1,21 @@
+import { useCallback } from 'react';
+import { useNavigate, useSearchParams } from 'react-router-dom';
+
+export default function Login() {
+  const navigate = useNavigate();
+  let [searchParams] = useSearchParams();
+
+  const login = useCallback(() => {
+    localStorage.setItem('token', '123213jdfjdkalfjakl');
+
+    // navigate(searchParams.get('from') || '/');
+
+    navigate({ pathname: searchParams.get('from') || '/' });
+  }, []);
+
+  return (
+    <div className="Login">
+      <button onClick={login}>登录</button>
+    </div>
+  );
+}

+ 26 - 0
20_React.js_VIP22/day-6/code/react-router-lazy/src/pages/Protected.jsx

@@ -0,0 +1,26 @@
+import { useNavigate } from 'react-router-dom';
+import { useAuth } from '../hooks/useAuth';
+
+export default function Protected() {
+  const navigate = useNavigate();
+
+  useAuth();
+
+  return (
+    <div className="Protected">
+      <h3>受保护页面——需要登录后才可以访问</h3>
+      <div>
+        <button
+          onClick={() => {
+            if (window.confirm('确定退出系统吗')) {
+              localStorage.clear();
+              navigate('/login');
+            }
+          }}
+        >
+          退出登录
+        </button>
+      </div>
+    </div>
+  );
+}

+ 14 - 0
20_React.js_VIP22/day-6/code/react-router-lazy/src/router/index.js

@@ -1,8 +1,10 @@
 import { createBrowserRouter } from 'react-router-dom';
 import Home from '../pages/Home';
+import Login from '../pages/Login';
 import { lazy, Suspense } from 'react';
 
 const About = lazy(() => import('../pages/About'));
+const Protected = lazy(() => import('../pages/Protected'));
 
 const router = createBrowserRouter([
   { path: '/', Component: Home },
@@ -14,6 +16,18 @@ const router = createBrowserRouter([
       </Suspense>
     ),
   },
+  {
+    path: '/protected',
+    element: (
+      <Suspense fallback={<h3>加载中...</h3>}>
+        <Protected />
+      </Suspense>
+    ),
+  },
+  {
+    path: '/login',
+    element: <Login />,
+  },
 ]);
 
 export default router;