React路由学习

官方文档:https://reactrouter.com/en/main

学习时以Tutorial(教程)为主

一、创建项目

//创建项目
npm create vite@latest [项目名] -- --template react//安装react-router
cd [项目名]
npm i react-router-dom localforage match-sorter sort-by

1、添加代码依赖

打开src/index.css,替换其中的内容

html {box-sizing: border-box;
}
*,
*:before,
*:after {box-sizing: inherit;
}body {font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen","Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",sans-serif;-webkit-font-smoothing: antialiased;-moz-osx-font-smoothing: grayscale;
}code {font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",monospace;
}html,
body {height: 100%;margin: 0;line-height: 1.5;color: #121212;
}
textarea,
input,
button {font-size: 1rem;font-family: inherit;border: none;border-radius: 8px;padding: 0.5rem 0.75rem;box-shadow: 0 0px 1px hsla(0, 0%, 0%, 0.2), 0 1px 2px hsla(0, 0%, 0%, 0.2);background-color: white;line-height: 1.5;margin: 0;
}
button {color: #3992ff;font-weight: 500;
}textarea:hover,
input:hover,
button:hover {box-shadow: 0 0px 1px hsla(0, 0%, 0%, 0.6), 0 1px 2px hsla(0, 0%, 0%, 0.2);
}button:active {box-shadow: 0 0px 1px hsla(0, 0%, 0%, 0.4);transform: translateY(1px);
}#contact h1 {display: flex;align-items: flex-start;gap: 1rem;
}
#contact h1 form {display: flex;align-items: center;margin-top: 0.25rem;
}
#contact h1 form button {box-shadow: none;font-size: 1.5rem;font-weight: 400;padding: 0;
}
#contact h1 form button[value="true"] {color: #a4a4a4;
}
#contact h1 form button[value="true"]:hover,
#contact h1 form button[value="false"] {color: #eeb004;
}form[action$="destroy"] button {color: #f44250;
}.sr-only {position: absolute;width: 1px;height: 1px;padding: 0;margin: -1px;overflow: hidden;clip: rect(0, 0, 0, 0);white-space: nowrap;border-width: 0;
}#root {display: flex;height: 100%;width: 100%;
}#sidebar {width: 22rem;background-color: #f7f7f7;border-right: solid 1px #e3e3e3;display: flex;flex-direction: column;
}#sidebar > * {padding-left: 2rem;padding-right: 2rem;
}#sidebar h1 {font-size: 1rem;font-weight: 500;display: flex;align-items: center;margin: 0;padding: 1rem 2rem;border-top: 1px solid #e3e3e3;order: 1;line-height: 1;
}#sidebar h1::before {content: url("data:image/svg+xml,%3Csvg width='25' height='18' viewBox='0 0 25 18' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M19.4127 6.4904C18.6984 6.26581 18.3295 6.34153 17.5802 6.25965C16.4219 6.13331 15.9604 5.68062 15.7646 4.51554C15.6551 3.86516 15.7844 2.9129 15.5048 2.32334C14.9699 1.19921 13.7183 0.695046 12.461 0.982805C11.3994 1.22611 10.516 2.28708 10.4671 3.37612C10.4112 4.61957 11.1197 5.68054 12.3363 6.04667C12.9143 6.22097 13.5284 6.3087 14.132 6.35315C15.2391 6.43386 15.3241 7.04923 15.6236 7.55574C15.8124 7.87508 15.9954 8.18975 15.9954 9.14193C15.9954 10.0941 15.8112 10.4088 15.6236 10.7281C15.3241 11.2334 14.9547 11.5645 13.8477 11.6464C13.244 11.6908 12.6288 11.7786 12.0519 11.9528C10.8353 12.3201 10.1268 13.3799 10.1828 14.6234C10.2317 15.7124 11.115 16.7734 12.1766 17.0167C13.434 17.3056 14.6855 16.8003 15.2204 15.6762C15.5013 15.0866 15.6551 14.4187 15.7646 13.7683C15.9616 12.6032 16.423 12.1505 17.5802 12.0242C18.3295 11.9423 19.1049 12.0242 19.8071 11.6253C20.5491 11.0832 21.212 10.2696 21.212 9.14192C21.212 8.01428 20.4976 6.83197 19.4127 6.4904Z' fill='%23F44250'/%3E%3Cpath d='M7.59953 11.7459C6.12615 11.7459 4.92432 10.5547 4.92432 9.09441C4.92432 7.63407 6.12615 6.44287 7.59953 6.44287C9.0729 6.44287 10.2747 7.63407 10.2747 9.09441C10.2747 10.5536 9.07172 11.7459 7.59953 11.7459Z' fill='black'/%3E%3Cpath d='M2.64217 17.0965C1.18419 17.093 -0.0034949 15.8971 7.72743e-06 14.4356C0.00352588 12.9765 1.1994 11.7888 2.66089 11.7935C4.12004 11.797 5.30772 12.9929 5.30306 14.4544C5.29953 15.9123 4.10366 17.1 2.64217 17.0965Z' fill='black'/%3E%3Cpath d='M22.3677 17.0965C20.9051 17.1046 19.7046 15.9217 19.6963 14.4649C19.6882 13.0023 20.8712 11.8017 22.3279 11.7935C23.7906 11.7854 24.9911 12.9683 24.9993 14.4251C25.0075 15.8866 23.8245 17.0883 22.3677 17.0965Z' fill='black'/%3E%3C/svg%3E%0A");margin-right: 0.5rem;position: relative;top: 1px;
}#sidebar > div {display: flex;align-items: center;gap: 0.5rem;padding-top: 1rem;padding-bottom: 1rem;border-bottom: 1px solid #e3e3e3;
}#sidebar > div form {position: relative;
}#sidebar > div form input[type="search"] {width: 100%;padding-left: 2rem;background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' class='h-6 w-6' fill='none' viewBox='0 0 24 24' stroke='%23999' stroke-width='2'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z' /%3E%3C/svg%3E");background-repeat: no-repeat;background-position: 0.625rem 0.75rem;background-size: 1rem;position: relative;
}#sidebar > div form input[type="search"].loading {background-image: none;
}#search-spinner {width: 1rem;height: 1rem;background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24'%3E%3Cpath stroke='%23000' strokeLinecap='round' strokeLinejoin='round' strokeWidth='2' d='M20 4v5h-.582m0 0a8.001 8.001 0 00-15.356 2m15.356-2H15M4 20v-5h.581m0 0a8.003 8.003 0 0015.357-2M4.581 15H9' /%3E%3C/svg%3E");animation: spin 1s infinite linear;position: absolute;left: 0.625rem;top: 0.75rem;
}@keyframes spin {from {transform: rotate(0deg);}to {transform: rotate(360deg);}
}#sidebar nav {flex: 1;overflow: auto;padding-top: 1rem;
}#sidebar nav a span {float: right;color: #eeb004;
}
#sidebar nav a.active span {color: inherit;
}i {color: #818181;
}
#sidebar nav .active i {color: inherit;
}#sidebar ul {padding: 0;margin: 0;list-style: none;
}#sidebar li {margin: 0.25rem 0;
}#sidebar nav a {display: flex;align-items: center;justify-content: space-between;overflow: hidden;white-space: pre;padding: 0.5rem;border-radius: 8px;color: inherit;text-decoration: none;gap: 1rem;
}#sidebar nav a:hover {background: #e3e3e3;
}#sidebar nav a.active {background: hsl(224, 98%, 58%);color: white;
}#sidebar nav a.pending {color: hsl(224, 98%, 58%);
}#detail {flex: 1;padding: 2rem 4rem;width: 100%;
}#detail.loading {opacity: 0.25;transition: opacity 200ms;transition-delay: 200ms;
}#contact {max-width: 40rem;display: flex;
}#contact h1 {font-size: 2rem;font-weight: 700;margin: 0;line-height: 1.2;
}#contact h1 + p {margin: 0;
}#contact h1 + p + p {white-space: break-spaces;
}#contact h1:focus {outline: none;color: hsl(224, 98%, 58%);
}#contact a[href*="twitter"] {display: flex;font-size: 1.5rem;color: #3992ff;text-decoration: none;
}
#contact a[href*="twitter"]:hover {text-decoration: underline;
}#contact img {width: 12rem;height: 12rem;background: #c8c8c8;margin-right: 2rem;border-radius: 1.5rem;object-fit: cover;
}#contact h1 ~ div {display: flex;gap: 0.5rem;margin: 1rem 0;
}#contact-form {display: flex;max-width: 40rem;flex-direction: column;gap: 1rem;
}
#contact-form > p:first-child {margin: 0;padding: 0;
}
#contact-form > p:first-child > :nth-child(2) {margin-right: 1rem;
}
#contact-form > p:first-child,
#contact-form label {display: flex;
}
#contact-form p:first-child span,
#contact-form label span {width: 8rem;
}
#contact-form p:first-child input,
#contact-form label input,
#contact-form label textarea {flex-grow: 2;
}#contact-form-avatar {margin-right: 2rem;
}#contact-form-avatar img {width: 12rem;height: 12rem;background: hsla(0, 0%, 0%, 0.2);border-radius: 1rem;
}#contact-form-avatar input {box-sizing: border-box;width: 100%;
}#contact-form p:last-child {display: flex;gap: 0.5rem;margin: 0 0 0 8rem;
}#contact-form p:last-child button[type="button"] {color: inherit;
}#zero-state {margin: 2rem auto;text-align: center;color: #818181;
}#zero-state a {color: inherit;
}#zero-state a:hover {color: #121212;
}#zero-state:before {display: block;margin-bottom: 0.5rem;content: url("data:image/svg+xml,%3Csvg width='50' height='33' viewBox='0 0 50 33' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M38.8262 11.1744C37.3975 10.7252 36.6597 10.8766 35.1611 10.7128C32.8444 10.4602 31.9215 9.55475 31.5299 7.22456C31.3108 5.92377 31.5695 4.01923 31.0102 2.8401C29.9404 0.591789 27.4373 -0.416556 24.9225 0.158973C22.7992 0.645599 21.0326 2.76757 20.9347 4.94569C20.8228 7.43263 22.2399 9.5546 24.6731 10.2869C25.8291 10.6355 27.0574 10.8109 28.2646 10.8998C30.4788 11.0613 30.6489 12.292 31.2479 13.3051C31.6255 13.9438 31.9914 14.5731 31.9914 16.4775C31.9914 18.3819 31.6231 19.0112 31.2479 19.6499C30.6489 20.6606 29.9101 21.3227 27.696 21.4865C26.4887 21.5754 25.2581 21.7508 24.1044 22.0994C21.6712 22.834 20.2542 24.9537 20.366 27.4406C20.4639 29.6187 22.2306 31.7407 24.3538 32.2273C26.8686 32.8052 29.3717 31.7945 30.4415 29.5462C31.0032 28.3671 31.3108 27.0312 31.5299 25.7304C31.9238 23.4002 32.8467 22.4948 35.1611 22.2421C36.6597 22.0784 38.2107 22.2421 39.615 21.4443C41.099 20.36 42.4248 18.7328 42.4248 16.4775C42.4248 14.2222 40.9961 11.8575 38.8262 11.1744Z' fill='%23E3E3E3'/%3E%3Cpath d='M15.1991 21.6854C12.2523 21.6854 9.84863 19.303 9.84863 16.3823C9.84863 13.4615 12.2523 11.0791 15.1991 11.0791C18.1459 11.0791 20.5497 13.4615 20.5497 16.3823C20.5497 19.3006 18.1436 21.6854 15.1991 21.6854Z' fill='%23E3E3E3'/%3E%3Cpath d='M5.28442 32.3871C2.36841 32.38 -0.00698992 29.9882 1.54551e-05 27.0652C0.00705187 24.1469 2.39884 21.7715 5.32187 21.7808C8.24022 21.7878 10.6156 24.1796 10.6063 27.1027C10.5992 30.0187 8.20746 32.3941 5.28442 32.3871Z' fill='%23E3E3E3'/%3E%3Cpath d='M44.736 32.387C41.8107 32.4033 39.4096 30.0373 39.3932 27.1237C39.3769 24.1984 41.7428 21.7973 44.6564 21.7808C47.5817 21.7645 49.9828 24.1305 49.9993 27.0441C50.0156 29.9671 47.6496 32.3705 44.736 32.387Z' fill='%23E3E3E3'/%3E%3C/svg%3E%0A");
}#error-page {display: flex;flex-direction: column;align-items: center;justify-content: center;width: 100%;
}

创建src/contacts.js 

import localforage from "localforage";
import { matchSorter } from "match-sorter";
import sortBy from "sort-by";export async function getContacts(query) {await fakeNetwork(`getContacts:${query}`);let contacts = await localforage.getItem("contacts");if (!contacts) contacts = [];if (query) {contacts = matchSorter(contacts, query, { keys: ["first", "last"] });}return contacts.sort(sortBy("last", "createdAt"));
}export async function createContact() {await fakeNetwork();let id = Math.random().toString(36).substring(2, 9);let contact = { id, createdAt: Date.now() };let contacts = await getContacts();contacts.unshift(contact);await set(contacts);return contact;
}export async function getContact(id) {await fakeNetwork(`contact:${id}`);let contacts = await localforage.getItem("contacts");let contact = contacts.find(contact => contact.id === id);return contact ?? null;
}export async function updateContact(id, updates) {await fakeNetwork();let contacts = await localforage.getItem("contacts");let contact = contacts.find(contact => contact.id === id);if (!contact) throw new Error("No contact found for", id);Object.assign(contact, updates);await set(contacts);return contact;
}export async function deleteContact(id) {let contacts = await localforage.getItem("contacts");let index = contacts.findIndex(contact => contact.id === id);if (index > -1) {contacts.splice(index, 1);await set(contacts);return true;}return false;
}function set(contacts) {return localforage.setItem("contacts", contacts);
}// fake a cache so we don't slow down stuff we've already seen
let fakeCache = {};async function fakeNetwork(key) {if (!key) {fakeCache = {};}if (fakeCache[key]) {return;}fakeCache[key] = true;return new Promise(res => {setTimeout(res, Math.random() * 800);});
}

删除src中的其他文件,仅保留以下文件

二、路由使用

1、添加路由对象

写在main.jsx文件中

import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.jsx'
import './index.css'//创建路由对象
import { createBrowserRouter as Router, createBrowserRouter } from 'react-router-dom'
import { RouterProvider } from 'react-router-dom'const  router = createBrowserRouter([       //里面是一个数组,每个元素是一个对象,对象中包含path和component属性{path: '/',//component: () => <h1>Home</h1>,element: <h1>Home</h1>,},])ReactDOM.createRoot(document.getElementById('root')).render(<React.StrictMode>{/* 配置使用路由对象 */}<RouterProvider router={router}></RouterProvider></React.StrictMode>,
)

成功运行截图:

 2、创建根组件,并使用

创建routes/root.jsx,并写入内容:

export default function Root() {return (<><div id="sidebar"><h1>React Router Contacts</h1><div><form id="search-form" role="search"><inputid="q"aria-label="Search contacts"placeholder="Search"type="search"name="q"/><divid="search-spinner"aria-hiddenhidden={true}/><divclassName="sr-only"aria-live="polite"></div></form><form method="post"><button type="submit">New</button></form></div><nav><ul><li><a href={`/contacts/1`}>Your Name</a></li><li><a href={`/contacts/2`}>Your Friend</a></li></ul></nav></div><div id="detail"></div></>);}

 改写main.jsx中的内容

 运行结果如下:

3、失败处理

创建src/error-page.jsx,并添加代码如下:

import { useRouteError } from "react-router-dom";export default function ErrorPage() {const error = useRouteError();console.error(error);return (<div id="error-page"><h1>Oops!</h1><p>Sorry, an unexpected error has occurred.</p><p><i>{error.statusText || error.message}</i></p></div>);
}

在main.jsx中配置根路由,如下:

效果图如下:

4、路由嵌套

(1)创建组件:创建routes/contact.jsx,并写入内容:

import { Form } from "react-router-dom";export default function Contact() {const contact = {first: "Your",last: "Name",avatar: "https://placekitten.com/g/200/200",twitter: "your_handle",notes: "Some notes",favorite: true,};return (<div id="contact"><div><imgkey={contact.avatar}src={contact.avatar || null}/></div><div><h1>{contact.first || contact.last ? (<>{contact.first} {contact.last}</>) : (<i>No Name</i>)}{" "}<Favorite contact={contact} /></h1>{contact.twitter && (<p><atarget="_blank"href={`https://twitter.com/${contact.twitter}`}>{contact.twitter}</a></p>)}{contact.notes && <p>{contact.notes}</p>}<div><Form action="edit"><button type="submit">Edit</button></Form><Formmethod="post"action="destroy"onSubmit={(event) => {if (!confirm("Please confirm you want to delete this record.")) {event.preventDefault();}}}><button type="submit">Delete</button></Form></div></div></div>);
}function Favorite({ contact }) {// yes, this is a `let` for laterlet favorite = contact.favorite;return (<Form method="post"><buttonname="favorite"value={favorite ? "false" : "true"}aria-label={favorite? "Remove from favorites": "Add to favorites"}>{favorite ? "★" : "☆"}</button></Form>);
}
在路由层面实现嵌套

编辑main.jsx文件:

在组件层面实现嵌套

编辑root.jsx文件

效果如下:

Link与a链接的不同

将<a href>改写成<Link to>

将<a>标签替换成<Link>组件的原因,减少请求次数,节约资源。

具体改动如下:

5、加载数据

改写root.jsx中的代码

6、创建信息

将<form>改为<Form>

封装action

绑定路由:

<Form>标签没有action属性,点击New按钮,数据会重新提交到当前页面。

效果如下:

7、使用URL Params获取具体信息

封装loader函数,解构params参数

绑定路由:

效果如下:

编辑更新信息

没写method,默认是get请求

创建routes/edit.jsx,并写入以下内容:

import { Form, useLoaderData } from "react-router-dom";export default function EditContact() {const { contact } = useLoaderData();return (<Form method="post" id="contact-form"><p><span>Name</span><inputplaceholder="First"aria-label="First name"type="text"name="first"defaultValue={contact?.first}/><inputplaceholder="Last"aria-label="Last name"type="text"name="last"defaultValue={contact?.last}/></p><label><span>Twitter</span><inputtype="text"name="twitter"placeholder="@jack"defaultValue={contact?.twitter}/></label><label><span>Avatar URL</span><inputplaceholder="https://example.com/avatar.jpg"aria-label="Avatar URL"type="text"name="avatar"defaultValue={contact?.avatar}/></label><label><span>Notes</span><textareaname="notes"defaultValue={contact?.notes}rows={6}/></label><p><button type="submit">Save</button><button type="button">Cancel</button></p></Form>);
}

绑定路由

效果如下:

保存更新信息

在edit.jsx文件写入以下代码:

绑定路由:

此时,点击No Name可以对信息进行修改。

重定向到修改信息页面

在根路由页面重新表单提交动作即可

最终效果,点击New按钮,直接进行信息编辑

8、导航链接状态处理

选中信息,在导航栏设置高亮

将root.jsx文件中的<Link>替换成<NaviLink>即可

效果如下:

9、导航对象

修改root.jsx文件

10、删除联系信息

给delete按钮包裹form表单,用于拦截请求。

创建目标路由:创建routes/destroy.jsx,并下入:

import { redirect } from 'react-router-dom'
import {deleteContact} from '../contacts'export async function action({params}){await deleteContact(params.contactId)return redirect('/')
}

绑定路由:

效果如下:

11、上下文错误处理

人为抛出错误信息:

机制:局部大于全局

12、默认子路由

创建routes/index.jsx文件,写入代码:

export default function Index() {return (<p id="zero-state">This is a demo for React Router.<br />Check out{" "}<a href="https://reactrouter.com">the docs at reactrouter.com</a>.</p>);
}

配置子路由:

13、回退操作

给button添加点击事件

14、搜索框查询条件

将<form>标签改为<Form>用于拦截请求

获取

15、完成标星功能

在contact.jsx文件中添加切换标星状态的函数

//切换标星状态
export async function action({ request, params }) {let formData = await request.formData();return updateContact(params.contactId, {favorite: formData.get("favorite") === "true",});
}

将<Form>标签替换成<fetcher.Form>标签

配置路由

效果如下:

三、react路由的简单记录

1、创建基本的React-Router

1、在项目中安装React-Router
npm install react-router-dom或者yarn add react-router-dom

2、创建路由配置

在项目中创建一个路由配置文件,例如routes.js,用于定义我们的路由配置。可以在路由配置文件中导入react-router-dom中的相关组件,例如BrowserRouterRouteSwitch等。

// routes.js
import React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import Home from './components/Home';
import About from './components/About';
import Contact from './components/Contact';function App() {return (<Router><Switch><Route path="/" exact component={Home} /><Route path="/about" component={About} /><Route path="/contact" component={Contact} /></Switch></Router>);
}export default App;

3、在根组件中使用路由配置

在项目的根组件中引入路由配置,并在组件中使用定义的路由组件。

// App.js
import React from 'react';
import Routes from './routes';function App() {return (<div><h1>My React-Router App</h1><Routes /></div>);
}export default App;

4、使用Link组件进行导航

在组件中使用Link组件进行导航,例如在导航栏或者页面中的链接,使用to属性指定要导航的路径。

// Navbar.js
import React from 'react';
import { Link } from 'react-router-dom';function Navbar() {return (<nav><ul><li><Link to="/">Home</Link></li><li><Link to="/about">About</Link></li><li><Link to="/contact">Contact</Link></li></ul></nav>);
}export default Navbar;

这样,我们就完成了一个基本的React-Router应用的创建,并实现了简单的导航功能。

5、基于路由的页面布局

使用React-Router,我们可以实现基于路由的页面布局,从而根据不同的路由显示不同的页面布局。例如,在某些路由下显示不同的导航栏、侧边栏或者页脚。

// routes.js
import React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import Home from './components/Home';
import About from './components/About';
import Contact from './components/Contact';
import Navbar from './components/Navbar';function App() {return (<Router><Navbar /> {/* 在这里引入导航栏组件 */}<Switch><Route path="/" exact component={Home} /><Route path="/about" component={About} /><Route path="/contact" component={Contact} /></Switch></Router>);
}export default App;

在上面的例子中,我们在路由配置中引入了一个导航栏组件Navbar,并放置在Switch组件之前,这样在不同的路由下会渲染不同的导航栏。

6、动态路由配置

React-Router还支持动态路由配置,可以处理不同页面的路由需求,例如嵌套路由、参数传递和路由守卫等。

嵌套路由

可以在路由配置中定义嵌套路由,例如在一个页面下有多个子页面,可以通过嵌套路由来实现。

// routes.js
import React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import Home from './components/Home';
import About from './components/About';
import Contact from './components/Contact';
import Products from './components/Products';
import ProductDetails from './components/ProductDetails';function App() {return (<Router><Navbar /><Switch><Route path="/" exact component={Home} /><Route path="/about" component={About} /><Route path="/contact" component={Contact} /><Route path="/products" exact component={Products} /> {/* 定义嵌套路由 */}<Route path="/products/:id" component={ProductDetails} /> {/* 定义带参数的嵌套路由 */}</Switch></Router>);
}export default App;

在上面的例子中,我们在/products路由下定义了一个嵌套路由/products/:id,其中:id表示参数,可以在ProductDetails组件中通过props.match.params.id获取传递的参数值。

参数传递及处理

React-Router支持在路由之间传递参数,包括路径参数和查询参数。可以在路由中定义参数,并在组件中通过props.match.paramsprops.location.search来获取参数值。

// routes.js
import React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import Home from './components/Home';
import About from './components/About';
import Contact from './components/Contact';
import Products from './components/Products';
import ProductDetails from './components/ProductDetails';function App() {return (<Router><Navbar /><Switch><Route path="/" exact component={Home} /><Route path="/about" component={About} /><Route path="/contact" component={Contact} /><Route path="/products"exact component={Products} /><Route path="/products/:id" component={ProductDetails} /></Switch></Router>);}export default App;

在上面的例子中,我们在/products/:id路由中定义了一个参数:id,可以通过props.match.params.idProductDetails组件中获取传递的参数值。

路由守卫实现权限控制

React-Router提供了路由守卫(Route Guard)功能,可以在路由渲染之前进行权限验证,例如登录验证、权限验证等。

// PrivateRoute.js
import React from 'react';
import { Route, Redirect } from 'react-router-dom';// 自定义私有路由守卫组件
const PrivateRoute = ({ component: Component, isAuthenticated, ...rest }) => {return (<Route{...rest}render={(props) =>isAuthenticated ? ( // 判断是否登录<Component {...props} />) : (<Redirect to="/login" /> // 未登录则跳转到登录页面)}/>);
};export default PrivateRoute;

在上面的例子中,我们定义了一个私有路由守卫组件PrivateRoute,通过isAuthenticated参数来判断用户是否已登录,如果已登录,则渲染目标组件,否则跳转到登录页面。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/21967.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从关键新闻和最新技术看AI行业发展(2024.5.20-6.2第二十四期) |【WeThinkIn老实人报】

写在前面 【WeThinkIn老实人报】旨在整理&挖掘AI行业的关键新闻和最新技术&#xff0c;同时Rocky会对这些关键信息进行解读&#xff0c;力求让读者们能从容跟随AI科技潮流。也欢迎大家提出宝贵的优化建议&#xff0c;一起交流学习&#x1f4aa; 欢迎大家关注Rocky的公众号&…

使用Xshell一键在多个会话中执行多个命令

背景 平时在工作中经常通过ssh远程操作Linux&#xff0c;由于我们负责的服务部署在超过5台服务器&#xff08;相同的代码及路径&#xff09;&#xff0c;每次发布后执行重启都得重复操作5次关闭、检查、启动、查看日志&#xff0c;特别繁琐。 后来发现Xshell 7可以录制脚本&am…

大模型时代的具身智能系列专题(十一)

UMass Amherst 淦创团队 淦创是马萨诸塞大学阿默斯特分校的一名教员&#xff0c;也是麻省理工学院- ibm沃森人工智能实验室的研究经理。在麻省理工学院博士后期间&#xff0c;和Antonio Torralba教授、Daniela Rus教授和Josh Tenenbaum教授一起工作。在此之前&#xff0c;在清…

Ai绘画工具Stable Diffusion,手把手教你训练你的专属Lora模型,神级教程建议收藏!

哈喽&#xff0c;大家好&#xff0c;我是设计师阿威。 今天给大家带来的是Stable Diffusion训练Lora的教程&#xff0c;希望对大家有帮助。 一、硬件要求 我们知道Stable Diffusion WebUI对显卡要求比较高&#xff0c;同样Lora训练对显卡要求更高&#xff0c;所以要想训练一…

【Endnote】如何在word界面加载Endnote

如何在word界面加载Endnote 方法1&#xff1a;方法2&#xff1a;从word入手方法3&#xff1a;从CWYW入手参考 已下载EndNote,但Word中没有显示EndNote&#xff0c;应如何加载显示呢&#xff1f; 方法1&#xff1a; 使用EndNote的Configure EndNote.exe 。 具体步骤为&#x…

通过异步请求上传文件到七牛云

一、准备工作 创建账号、创建空间这种大家自己研究就行(有手就行) 只需要根据步骤查找对应文档 从服务端获取七牛云上传的token,生成token参考官方文档 在七牛云文档查找上传的存储区域 在七牛云控制台找到空间管理的cdn加速域名 二、后台token获取 基于准备工作1中&…

将 KNX 接入 Home Assistant 之三 功能配置

万事俱备只欠东风&#xff0c;不管是ETS还是HA都需要配置才能使用。还是期待以后发展到可以开箱即用。 KNXD的配置 在 《将 KNX 接入 Home Assistant 之二 准备软件》&#xff0c;我们已经装好了KNXD的插件&#xff0c;现在就需要进行配置了 配置的界面 注意图中加框的选择&…

UI 自动化测试(Selenuim + Java )

关于 UI 自动化测试工具 selenuim Java 的环境搭建推荐看SeleniumJava 环境搭建 什么是自动化测试&#xff1f; 自动化测试指软件测试的自动化&#xff0c;在预设状态下运行应用程序或者系统&#xff0c;预设条件包括正常和异常&#xff0c;最后评估运行结果。将人为驱动的测…

分享两种论文降重最有效的方法(论文降重网站)

论文降重最有效的方法可以分为手动方法和使用降重网站两种方法。以下是详细的分析和归纳&#xff1a; 手动方法 删减冗余内容&#xff1a;对于论文中的某些内容&#xff0c;特别是信息冗余或不必要的描述&#xff0c;可以通过删减和简化来减少篇幅。确保每一段落和每一个例子都…

[FreeRTOS 基础知识] 栈

文章目录 栈的概念使用C语言实现 栈通过代码反汇编解析 栈 栈的概念 所谓的栈就是一块空间的内存&#xff0c;CPU的SP寄存器指向它&#xff0c;它可以用于函数调用&#xff0c;局部变量&#xff0c;多任务系统里保存现场。 使用C语言实现 栈 volatile int num0;int fun_b(vol…

i.MX8MP平台开发分享(RDC资源分配控制器篇)

1.spec RDC 配置信息被发送到结构端口、内存垫片、信号控制器和外设&#xff0c;以根据域分配控制访问。 结构使用与每个端口相关的域标识符&#xff0c;将此信息与总线事务一起包含在内。当从属加密垫圈遇到总线事务时&#xff0c;它会将事务域 ID 与 RDC 提供的允许域列表进…

串口通讯、RS485、232、SPI、I2C

串行通信与并行通信的比较 1.同步和异步 同步串口通信&#xff08;Synchronous Serial Communication&#xff09; 异步串口通信&#xff08;Asynchronous Serial Communication&#xff09; 比较 2.全双工&#xff0c;半双工&#xff0c;单工 全双工&#xff08;Full Du…

Midjourney绘画参数设置详解

在数字艺术和设计领域&#xff0c;Midjourney是一款强大的绘画工具&#xff0c;它允许艺术家和设计师以数字方式创作出精美的图像。为了充分发挥Midjourney的潜力&#xff0c;正确设置其绘画参数至关重要。本文将深入探讨Midjourney的绘画参数设置&#xff0c;帮助用户更好地掌…

第十五届蓝桥杯物联网试题(国赛)

好&#xff0c;很好&#xff0c;国赛直接来个阅读理解&#xff0c;我猛做4个小时40分钟&#xff0c;cpu都干冒烟了&#xff0c;也算是勉强做完吧&#xff0c;做的很仓促&#xff0c;没多检查就交了&#xff0c;方波不会&#xff0c;A板有个指示灯没做&#xff0c;其他应该都还凑…

使用EMQX搭建MQTT服务

简介&#xff1a;EMQX 是一款开源的大规模分布式 MQTT 消息服务器&#xff0c;功能丰富&#xff0c;专为物联网和实时通信应用而设计。EMQX 5.0 单集群支持 MQTT 并发连接数高达 1 亿条&#xff0c;单服务器的传输与处理吞吐量可达每秒百万级 MQTT 消息&#xff0c;同时保证毫秒…

内存动态管理

内存动态管理 1 .为什么要有动态内存分配 我们已经掌握的内存开辟⽅式有&#xff1a; int val 20;//在栈空间上开辟四个字节 char arr[10] {0};//在栈空间上开辟10个字节的连续空间但是上述的开辟空间的⽅式有两个特点&#xff1a; • 空间开辟⼤⼩是固定的。 • 数组在…

SQL Developer 小贴士:备份和恢复连接信息

问题与概念 有时候SQL Developer需要重装&#xff0c;能备份和恢复连接信息就比较重要。 SQL Developer提供连接的导出和导入功能。 导出连接 第一步&#xff1a;选择连接。 第2步&#xff1a;指定输出文件&#xff0c;例如sqldconns.json 第3步&#xff1a;因为连接中可…

netty LengthFieldBasedFrameDecoder 根据动态长度分包粘包

如下数据格式 在方法&#xff1a; // Integer.MAX_VALUE, // maxFrameLength: 最大允许的帧长度// 4, // lengthFieldOffset: 长度字段在帧中的偏移量&#xff0c;这里是在帧头之后// 4, // lengthFieldLength: 长度字段的长度&#xff0c;4字节表示32位整数// 0, // …

CentOS7配置国内清华源并安装docker-ce以及配置docker加速

说明 由于国内访问国外的网站包括docker网站&#xff0c;由于种种的原因经常打不开&#xff0c;或无法访问&#xff0c;所以替换成国内的软件源和国内镜像就是非常必要的了&#xff0c;这里整理了我安装配置的基本的步骤。 国内的软件源有很多&#xff0c;这里选择清华源作为…

2024下半年Meme币趋势分析

随着加密货币市场的不断演变&#xff0c;Meme币在过去几年中引起了广泛关注。虽然这些数字资产最初因其搞笑和讽刺的性质而受到欢迎&#xff0c;但它们在市场上的表现和投资潜力也逐渐被重视。2024年下半年&#xff0c;Meme币市场将迎来新的趋势和挑战。本篇文章将探讨Meme币的…