探討JWT身份校驗(yàn)與React-router無(wú)縫集成
引言
這篇文章想跟大家聊聊 在React Router 中使用 JWT
在這篇文章中,我們將探討 JWT 身份校驗(yàn)與 React 和 React-router 的無(wú)縫集成。 我們還將學(xué)習(xí)如何處理公共路由、受校驗(yàn)保護(hù)路由,以及如何利用 axios 庫(kù)通過(guò)身份驗(yàn)證令牌(token)發(fā)出 API 請(qǐng)求。
創(chuàng)建一個(gè) React 項(xiàng)目
使用下方的指令會(huì)為我們創(chuàng)建一個(gè)項(xiàng)目
$ npm create vite@latest react-jwt-cn
然后我們選擇 react
和 javascript
作為我們的框架和語(yǔ)言。在項(xiàng)目開(kāi)始之前,我們要確保所有的依賴都已經(jīng)被安裝,所以我們要先執(zhí)行
$ npm install
安裝完畢后,在項(xiàng)目的根目錄下,我們可以運(yùn)行下面的指令來(lái)啟動(dòng)我們的項(xiàng)目
$ npm run dev
我們通過(guò)這些步驟來(lái)讓我們的 React 項(xiàng)目順利啟動(dòng)和運(yùn)行
安裝 React-Router 和 Axios
在我們繼續(xù)之前,要確保我們已經(jīng)為我們的項(xiàng)目安裝了必要的依賴項(xiàng)。 我們將從安裝 react-router v6 開(kāi)始,它將處理我們的 React 應(yīng)用程序中的路由。 此外,我們將安裝 Axios,這是一個(gè)用于發(fā)送 API 請(qǐng)求的庫(kù)。 通過(guò)執(zhí)行這些步驟,我們將配備實(shí)現(xiàn)無(wú)縫路由和執(zhí)行高效 API 通信所需的工具。 讓我們從安裝這些依賴項(xiàng)開(kāi)始。
$ npm install react-router-dom axios
在 React 中創(chuàng)建 AuthProvider 和 AuthContext
接下來(lái)我們要實(shí)現(xiàn)的就是 JWT 身份驗(yàn)證的功能。在這個(gè)小節(jié)中我們將創(chuàng)建一個(gè) AuthProvider
組件和一個(gè)關(guān)聯(lián)的 AuthContext
。這將協(xié)助我們?cè)谡麄€(gè)應(yīng)用中存儲(chǔ)和共享 JWT 身份驗(yàn)證相關(guān)的數(shù)據(jù)和函數(shù)
在 src > provider
下創(chuàng)建 authProvider.js
。然后我們來(lái)探 AuthProvider
和 AuthContext
的實(shí)現(xiàn)
- 導(dǎo)入必要的模塊和依賴包:
- 導(dǎo)入
axios
用于發(fā)送 API 請(qǐng)求 - 從
react
導(dǎo)入createContext
useContext
useEffect
useMemo
以及useState
import axios from "axios"; import { createContext, useContext, useEffect, useMemo, useState, } from "react";
- 使用
createContext()
來(lái)創(chuàng)建一個(gè)用于身份驗(yàn)證的上下文 createContext()
創(chuàng)建的空的上下文是用于在組件之間共享身份驗(yàn)證的數(shù)據(jù)和函數(shù)的
const AuthContext = createContext();
- 創(chuàng)建 AuthProvider 組件
- 這個(gè)組件是用于作為身份驗(yàn)證上下文 的 provider
- 它接收 children 作為 prop,代表將有權(quán)訪問(wèn)身份驗(yàn)證上下文的子組件。
const AuthProvider = ({ children }) => { // 組件內(nèi)容寫(xiě)在這里 };
- 使用
useState
定義一個(gè)名為token
的 state token
代表的是身份驗(yàn)證的令牌- 如果令牌數(shù)據(jù)存在的話,我們將通過(guò)
localStorage.getItem("token")
來(lái)獲取它
const [token, setToken_] = useState(localStorage.getItem("token"));
創(chuàng)建
setToken
函數(shù)來(lái)更新身份驗(yàn)證的令牌數(shù)據(jù)這個(gè)函數(shù)將會(huì)用于更新身份驗(yàn)證的令牌
它使用
setToken_
函數(shù)更新令牌數(shù)據(jù)并且將更新之后的數(shù)據(jù)通過(guò)localStorage.setItem()
存儲(chǔ)在本地環(huán)境
const setToken = (newToken) => { setToken_(newToken); };
使用
useEffect()
來(lái)設(shè)置 axios 默認(rèn)的身份驗(yàn)證請(qǐng)求頭并且將身份驗(yàn)證的令牌數(shù)據(jù)保存到本地每當(dāng)
token
更新, 這個(gè) effect 函數(shù)都會(huì)執(zhí)行如果
token
存在,它將被設(shè)置為 axios 的請(qǐng)求頭并且保存到本地 localStorage 中如果
token
是 null 或者 undefined ,它將移除對(duì)應(yīng)的 axios 請(qǐng)求頭以及本地身份驗(yàn)證相關(guān)的 localStorage 的數(shù)據(jù)
useEffect(() => { if (token) { axios.defaults.headers.common["Authorization"] = "Bearer " + token; localStorage.setItem('token',token); } else { delete axios.defaults.headers.common["Authorization"]; localStorage.removeItem('token') } }, [token]);
使用
useMemo
創(chuàng)建記憶化的上下文這個(gè)上下文包含
token
和setToken
函數(shù)token 的值會(huì)被作為記憶化的依賴項(xiàng)(如果 token 不變,則不會(huì)重新渲染)
const contextValue = useMemo( () => ({ token, setToken, }), [token] );
給自組件注入身份驗(yàn)證的上下文
使用
AuthContext.Provider
包裹子組件把 contextValue 作為 provider 的值傳入
return ( <AuthContext.Provider value={contextValue}> {children} </AuthContext.Provider> );
導(dǎo)出 useAuth 這個(gè) hook ,以供外部使用到身份驗(yàn)證這個(gè) context
useAuth 是一個(gè)自定義的 hook,它可以讓子組件很方便的訪問(wèn)到身份驗(yàn)證信息
export const useAuth = () => { return useContext(AuthContext); };
- 默認(rèn)導(dǎo)出 AuthProvider
export default AuthProvider;
完整代碼
import axios from "axios"; import { createContext, useContext, useEffect, useMemo, useState, } from "react"; const AuthContext = createContext(); const AuthProvider = ({ children }) => { const [token, setToken_] = useState(localStorage.getItem("token")); const setToken = (newToken) => { setToken_(newToken); }; useEffect(() => { if (token) { axios.defaults.headers.common["Authorization"] = "Bearer " + token; localStorage.setItem('token',token); } else { delete axios.defaults.headers.common["Authorization"]; localStorage.removeItem('token') } }, [token]); const contextValue = useMemo( () => ({ token, setToken, }), [token] ); return ( <AuthContext.Provider value={contextValue}> {children} </AuthContext.Provider> ); }; export const useAuth = () => { return useContext(AuthContext); }; export default AuthProvider;
小結(jié),此代碼使用 React 的 context API 設(shè)置身份驗(yàn)證上下文。 它通過(guò) context 向子組件提供身份驗(yàn)證令牌和 setToken 函數(shù)。 它還確保在身份驗(yàn)證令牌更新時(shí)可以及時(shí)更新 axios 中的默認(rèn)授權(quán)請(qǐng)求頭。
為 JWT 身份驗(yàn)證創(chuàng)建路由
為了能夠更高效的組織路由,我們將創(chuàng)建一個(gè) src > routes
目錄。在這個(gè)目錄里,我們將創(chuàng)建一個(gè) index.jsx
文件,這個(gè)文件用來(lái)作為定義整個(gè)應(yīng)用路由的入口。通過(guò)在單獨(dú)的文件夾中構(gòu)建我們的路由,我們可以保持清晰且易于管理的路由結(jié)構(gòu)。讓我們繼續(xù)創(chuàng)建路由并探索如何將 JWT 身份驗(yàn)證集成到我們的 React 應(yīng)用程序中。
為身份驗(yàn)證路由創(chuàng)建受保護(hù)路由組件
為了保護(hù)我們身份驗(yàn)證的路由并防止未經(jīng)授權(quán)的訪問(wèn),我們將創(chuàng)建一個(gè)名為 ProtectedRoute
的組件。這個(gè)組件將包裹我們的身份驗(yàn)證路由,以確保只有被授權(quán)的用戶才能夠訪問(wèn)。通過(guò)現(xiàn)實(shí)這個(gè)組件,我們可以輕松完成身份驗(yàn)證需求并提供良好的用戶體驗(yàn)。我們將在 src > routes
下創(chuàng)建 ProtectedRoute.jsx
文件
- 首先我們要從
react-router-dom
中導(dǎo)入必要的依賴
import { Navigate, Outlet } from "react-router-dom"; import { useAuth } from "../provider/authProvider";
- 定義
ProtectedRoute
組件,讓它包裹我們所有的需要鑒權(quán)的路由
export const ProtectedRoute = () => { const { token } = useAuth(); // 判斷用戶是否有權(quán)限 if (!token) { // 如果沒(méi)有授權(quán),則跳轉(zhuǎn)到登錄頁(yè)面 return <Navigate to="/login" />; } // 如果已經(jīng)授權(quán),則直接渲染子組件 return <Outlet />; };
- 在
ProtectedRoute
組件中,我們通過(guò) AuthContext 提供的自定義 hook (useAuth) 來(lái)獲取 token 信息 - 接下來(lái)我們檢查 token 是否存在。如果用戶沒(méi)有被授權(quán)( token 是 faslse 或者是 null ),我們將把路由導(dǎo)航到登錄頁(yè)面(
/login
) - 如果用戶被授權(quán)了,我們將使用 Outlet 組件來(lái)渲染子路由。Outlet 組件充當(dāng)占位符,顯示父路由中定義的子組件。
小結(jié),ProtectedRoute
組件充當(dāng)了身份驗(yàn)證的路由的守衛(wèi)。 如果用戶未通過(guò)身份驗(yàn)證,他們將被重定向到登錄頁(yè)面。 如果用戶通過(guò)身份驗(yàn)證,則 ProtectedRoute
組件中定義的子路由將使用 Outlet
組件呈現(xiàn)。
上述代碼使我們能夠根據(jù)用戶的身份驗(yàn)證狀態(tài)輕松保護(hù)特定路由并控制訪問(wèn),從而在我們的 React 應(yīng)用程序中提供安全的導(dǎo)航體驗(yàn)。
深入探索路由
現(xiàn)在我們已經(jīng)有了 ProtectedRoute
組件和身份驗(yàn)證上下文,我們可以繼續(xù)定義我們的路由。通過(guò)區(qū)分公共路由、受校驗(yàn)保護(hù)路由和非認(rèn)證用戶路由,我們可以有效地處理基于 JWT 認(rèn)證的導(dǎo)航和訪問(wèn)控制。接下來(lái)我們將深入到 src > routes > index.jsx
文件并探索如何將 JWT 身份校驗(yàn)集成到我們的路由結(jié)構(gòu)中
導(dǎo)入必要的依賴
RouterProvider
和createBrowserRouter
用于配置和提供路由功能useAuth
運(yùn)行我們?cè)L問(wèn)身份校驗(yàn)的上下文ProtectedRoute
組件包裹著受校驗(yàn)路由
import { RouterProvider, createBrowserRouter } from "react-router-dom"; import { useAuth } from "../provider/authProvider"; import { ProtectedRoute } from "./ProtectedRoute";
定義路由組件
該函數(shù)組件充當(dāng)配置應(yīng)用程序路由的入口
const Routes = () => { const { token } = useAuth(); // 路由配置寫(xiě)在這里 };
使用 useAuth hook 訪問(wèn)身份校驗(yàn)令牌
調(diào)用 useAuth hook 可以從身份校驗(yàn)上下文中獲取令牌
const { token } = useAuth();
定義面向所有用戶的路由(公共路由)
routesForPublic
數(shù)組保護(hù)所有可被所有用戶訪問(wèn)的路由信息。每個(gè)路由信息對(duì)象包含一個(gè) path 和一個(gè) elementpath 屬性明確了路由的 URL 路徑,element 屬性指向該路由下需要渲染的 jsx 組件/元素
const routesForPublic = [ { path: "/service", element: <div>Service Page</div>, }, { path: "/about-us", element: <div>About Us</div>, }, ];
定義只有授權(quán)用戶可以訪問(wèn)的路由
routesForAuthenticatedOnly
數(shù)組包含只能由經(jīng)過(guò)身份驗(yàn)證的用戶訪問(wèn)的路由對(duì)象。它包括包裝在 ProtectedRoute 組件中的受保護(hù)根路由(“/”)和使用 children 屬性定義的其他子路由。
const routesForAuthenticatedOnly = [ { path: "/", element: <ProtectedRoute />, children: [ { path: "/", element: <div>User Home Page</div>, }, { path: "/profile", element: <div>User Profile</div>, }, { path: "/logout", element: <div>Logout</div>, }, ], }, ];
定義只有沒(méi)有授權(quán)的用戶才可以訪問(wèn)的路由
routesForNotAuthenticatedOnly
數(shù)組包含沒(méi)有經(jīng)過(guò)身份驗(yàn)證的用戶訪問(wèn)的路由對(duì)象。它包含登錄路由(/login
)
const routesForNotAuthenticatedOnly = [ { path: "/", element: <div>Home Page</div>, }, { path: "/login", element: <div>Login</div>, }, ];
基于身份驗(yàn)證狀態(tài)來(lái)組合和判斷路由
createBrowserRouter 函數(shù)用于創(chuàng)建路由配置,它接收一個(gè)路由數(shù)組作為入?yún)?/p>
擴(kuò)展運(yùn)算符 (…) 用于將多個(gè)路由數(shù)組合并到一個(gè)數(shù)組
條件表達(dá)式 (
!token ? routesForNotAuthenticatedOnly : []
) 檢查用戶是否已通過(guò)身份驗(yàn)證(令牌存在)。 如果不是,則包含 routesForNotAuthenticatedOnly 數(shù)組; 否則,它包含一個(gè)空數(shù)組。
const router = createBrowserRouter([ ...routesForPublic, ...(!token ? routesForNotAuthenticatedOnly : []), ...routesForAuthenticatedOnly, ]);
使用 RouterProvider 注入路由配置
RouterProvider 組件包裝路由配置,使其可用于整個(gè)應(yīng)用程序
return <RouterProvider router={router} />;
完整代碼
import { RouterProvider, createBrowserRouter } from "react-router-dom"; import { useAuth } from "../provider/authProvider"; import { ProtectedRoute } from "./ProtectedRoute"; const Routes = () => { const { token } = useAuth(); // 公共路由配置 const routesForPublic = [ { path: "/service", element: <div>Service Page</div>, }, { path: "/about-us", element: <div>About Us</div>, }, ]; // 授權(quán)的用戶才可以訪問(wèn)的路由配置 const routesForAuthenticatedOnly = [ { path: "/", element: <ProtectedRoute />, // Wrap the component in ProtectedRoute children: [ { path: "/", element: <div>User Home Page</div>, }, { path: "/profile", element: <div>User Profile</div>, }, { path: "/logout", element: <div>Logout</div>, }, ], }, ]; // 沒(méi)有授權(quán)的用戶才可以訪問(wèn)的路由配置 const routesForNotAuthenticatedOnly = [ { path: "/", element: <div>Home Page</div>, }, { path: "/login", element: <div>Login</div>, }, ]; // 合并路由配置 const router = createBrowserRouter([ ...routesForPublic, ...(!token ? routesForNotAuthenticatedOnly : []), ...routesForAuthenticatedOnly, ]); return <RouterProvider router={router} />; }; export default Routes;
最后整合
現(xiàn)在我們已經(jīng)準(zhǔn)備好了 AuthContext
, AuthProvider
和 Routes
。讓我們把它們整合到 App.jsx
導(dǎo)入必要的組件和文件
AuthProvider
是從./provider/authProvider
文件中導(dǎo)入的組件。它為整個(gè)應(yīng)用程序提供了身份驗(yàn)證的上下文從
./routes
中導(dǎo)入Routes
。它定義了應(yīng)用路由
import AuthProvider from "./provider/authProvider"; import Routes from "./routes";
使用
AuthProvider
組件包裝Routes
組件AuthProvider
組件用于向應(yīng)用程序提供身份驗(yàn)證上下文。 它包裝了Routes
組件,使身份驗(yàn)證上下文可用于Routes
組件樹(shù)中的所有組件
return ( <AuthProvider> <Routes /> </AuthProvider> );
完整代碼
import AuthProvider from "./provider/authProvider"; import Routes from "./routes"; function App() { return ( <AuthProvider> <Routes /> </AuthProvider> ); } export default App;
實(shí)現(xiàn)登錄與登出
在 src > pages > Login.jsx
創(chuàng)建 登錄頁(yè)面
const Login = () => { const { setToken } = useAuth(); const navigate = useNavigate(); const handleLogin = () => { setToken("this is a test token"); navigate("/", { replace: true }); }; setTimeout(() => { handleLogin(); }, 3 * 1000); return <>Login Page</>; }; export default Login;
- 登錄組件是一個(gè)用于表示登錄頁(yè)面的函數(shù)組件
- 使用 useAuth hook 從身份校驗(yàn)上下文中導(dǎo)入
setToken
函數(shù) - 從
react-router-dom
中導(dǎo)入 navigate 函數(shù)用于處理路由跳轉(zhuǎn) - 在組件內(nèi)部,有一個(gè)
handleLogin
函數(shù),它使用上下文中的 setToken 函數(shù)設(shè)置測(cè)試令牌,并導(dǎo)航到主頁(yè) (“/”),并將替換選項(xiàng)(replace)設(shè)置為 true - setTimeout 函數(shù)用于模擬執(zhí)行
handleLogin
函數(shù)前的 3 秒延遲 - 組件為登錄頁(yè)返回 JSX,在此處充當(dāng)一個(gè)占位符文本
現(xiàn)在,我們?cè)?nbsp;src > pages > Logout.jsx
創(chuàng)建一個(gè) 登出頁(yè)面
import { useNavigate } from "react-router-dom"; import { useAuth } from "../provider/authProvider"; const Logout = () => { const { setToken } = useAuth(); const navigate = useNavigate(); const handleLogout = () => { setToken(); navigate("/", { replace: true }); }; setTimeout(() => { handleLogout(); }, 3 * 1000); return <>Logout Page</>; }; export default Logout;
- 在登出頁(yè)面中,我們調(diào)用了
setToken
函數(shù)并且沒(méi)有傳參,這相當(dāng)于調(diào)用setToken(null)
現(xiàn)在,我們將用更新后的版本替換路由組件中的登錄和登出組件
const routesForNotAuthenticatedOnly = [ { path: "/", element: <div>Home Page</div>, }, { path: "/login", element: <Login />, }, ];
在 routesForNotAuthenticatedOnly
數(shù)組中,“/login”
的 element
屬性設(shè)置為 <Login />
,表示當(dāng)用戶訪問(wèn) “/login”
路徑時(shí),會(huì)渲染 Login
組件
const routesForAuthenticatedOnly = [ { path: "/", element: <ProtectedRoute />, children: [ { path: "/", element: <div>User Home Page</div>, }, { path: "/profile", element: <div>User Profile</div>, }, { path: "/logout", element: <Logout />, }, ], }, ];
在 routesForAuthenticatedOnly
數(shù)組中,“/logout”
的 element
屬性設(shè)置為 <Logout />
,表示當(dāng)用戶訪問(wèn) “/logout”
路徑時(shí),會(huì)渲染 Logout
組件
測(cè)試流程
- 當(dāng)你第一次訪問(wèn)根頁(yè)面
/
時(shí),會(huì)看到routesForNotAuthenticatedOnly
數(shù)組中的 “ Home page ” - 如果你導(dǎo)航到
/login
,在延遲 3 秒后,將模擬登錄過(guò)程。 它將使用身份驗(yàn)證上下文中的 setToken 函數(shù)設(shè)置測(cè)試令牌,然后你將被react-router-dom
庫(kù)中的導(dǎo)航函數(shù)重定向到根頁(yè)面/
。 重定向后,你將從routesForAuthenticatedOnly
數(shù)組中看到 “User Home Page” - 如果你隨后訪問(wèn)
/logout
,在延遲 3 秒后,將模擬登出過(guò)程。 它將通過(guò)不帶任何參數(shù)調(diào)用setToken
函數(shù)來(lái)清除身份驗(yàn)證令牌,然后您將被重定向到根頁(yè)面/
。 由于你現(xiàn)在已登出,我們將從routesForNotAuthenticatedOnly
數(shù)組中看到 “ Home Page ”。
此流程演示了登錄和登出過(guò)程,其中用戶在經(jīng)過(guò)身份驗(yàn)證和未經(jīng)過(guò)身份驗(yàn)證的狀態(tài)之間轉(zhuǎn)換,并相應(yīng)地顯示相應(yīng)的路由。
以上就是本篇文章的全部?jī)?nèi)容,感謝大家對(duì)本文的支持~歡迎點(diǎn)贊收藏,在評(píng)論區(qū)留下你的高見(jiàn) ??????
其他
以上就是探討JWT身份校驗(yàn)與React-router無(wú)縫集成的詳細(xì)內(nèi)容,更多關(guān)于React Router JWT校驗(yàn)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- react-router?重新加回跳轉(zhuǎn)攔截功能詳解
- react-router-domV6嵌套路由實(shí)現(xiàn)詳解
- react-router?v6實(shí)現(xiàn)動(dòng)態(tài)路由實(shí)例
- react?路由權(quán)限動(dòng)態(tài)菜單方案配置react-router-auth-plus
- react-router-dom?v6?通過(guò)outlet實(shí)現(xiàn)keepAlive?功能的實(shí)現(xiàn)
- 詳解react-router-dom v6版本基本使用介紹
- react-router-domV6版本的路由和嵌套路由寫(xiě)法詳解
相關(guān)文章
Docker部署SpringBoot項(xiàng)目到云服務(wù)器的實(shí)現(xiàn)步驟
Docker作為一種輕量級(jí)的容器化技術(shù),為開(kāi)發(fā)者提供了快速、便捷的部署方案,本文主要介紹了Docker部署SpringBoot項(xiàng)目到云服務(wù)器,具有一定的參考價(jià)值,感興趣的可以了解一下2024-01-01React Js 微信禁止復(fù)制鏈接分享禁止隱藏右上角菜單功能
這篇文章主要介紹了React Js 微信禁止復(fù)制鏈接,分享,禁止隱藏右上角菜單的解決代碼,需要的朋友可以參考下2017-05-05React超詳細(xì)分析useState與useReducer源碼
我正在處理的組件是表單的時(shí)間輸入。表單相對(duì)復(fù)雜,并且是動(dòng)態(tài)生成的,根據(jù)嵌套在其他數(shù)據(jù)中的數(shù)據(jù)顯示不同的字段。我正在用useReducer管理表單的狀態(tài),到目前為止效果很好2022-11-11Ant?Design?組件庫(kù)按鈕實(shí)現(xiàn)示例詳解
這篇文章主要介紹了Ant?Design?組件庫(kù)按鈕實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪</P><P><BR>2022-08-08React18中請(qǐng)求數(shù)據(jù)的官方姿勢(shì)適用其他框架
這篇文章主要為大家介紹了官方回答在React18中請(qǐng)求數(shù)據(jù)的正確姿勢(shì)詳解,同樣也適用其他框架,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07React引入antd-mobile+postcss搭建移動(dòng)端
本文給大家分享React引入antd-mobile+postcss搭建移動(dòng)端的詳細(xì)流程,文末給大家分享我的一些經(jīng)驗(yàn)記錄使用antd-mobile時(shí)發(fā)現(xiàn)我之前配置的postcss失效了,防止大家踩坑,特此把解決方案分享到腳本之家平臺(tái),需要的朋友參考下吧2021-06-06react如何利用useRef、forwardRef、useImperativeHandle獲取并處理dom
這篇文章主要介紹了react如何利用useRef、forwardRef、useImperativeHandle獲取并處理dom,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2023-10-10使用React實(shí)現(xiàn)一個(gè)簡(jiǎn)單的待辦任務(wù)列表
這篇文章主要給大家介紹了使用React和Ant Design庫(kù)構(gòu)建的待辦任務(wù)列表應(yīng)用,它包含了可編輯的表格,用戶可以添加、編輯和完成任務(wù),以及保存任務(wù)列表數(shù)據(jù)到本地存儲(chǔ),文中有相關(guān)的代碼示例,需要的朋友可以參考下2023-08-08React實(shí)現(xiàn)生成和導(dǎo)出Word文檔的方法詳解
React是一個(gè)流行的JavaScript庫(kù),用于構(gòu)建現(xiàn)代前端應(yīng)用程序,本文將深入探討如何在React中生成和導(dǎo)出Word文檔,感興趣的小伙伴可以學(xué)習(xí)一下2023-09-09React+Antd+Redux實(shí)現(xiàn)待辦事件的方法
這篇文章主要介紹了React+Antd+Redux實(shí)現(xiàn)待辦事件的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03