学习React 的第七天 React-Router

324 阅读4分钟

“开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 7 天,点击查看活动详情

1. 简介

React和Vue一样都是单页面应用(SPA)加载单个HTML 页面并在用户与应用程序交互时动态更新该页面的Web应用程序,单页面应用需要实现多页面应用的效果就需要使用react-router-dom

2. 代码学习

1. 安装

pnpm i react-router-dom @types/react-router-dom

2. 创建三个页面

export function home() {
    return <div>
        <h1>home首页</h1>
    </div>
}

export function Cart() {
    return <div>
        <h1>汽车首页</h1>
    </div>
}

export function CartDetail() {
    return <div>
        <h1>汽车首页详细</h1>
    </div>
}
  1. 在项目核心文件main.tsx中导入路由相关组件
    1. 路由的类型
    import {HashRouter, BrowserRouter} from "react-router-dom";
    
    1. BrowserRouter 对应Vue的history模式
    2. HashRouter 对应Vue的hash模式
    3. 以上二选一使用
      ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
          <React.StrictMode>
              <BrowserRouter>
                  <App/>
              </BrowserRouter>
          </React.StrictMode>
      )
      

3. 页面注册到路由

```tsx
import { Route, Routes } from "react-router-dom";
import { Cart, CartDetail } from "./view/cart";
import Home from "./view/home";

function App() {
    return (
        <div className="App">
            <Routes>
                <Route path="/" element={<Home/>}></Route>
                <Route path="cart" element={<Cart/>}></Route>
            </Routes>
        </div>
    )
}
```
  1. Routes 路由容器,在它的内部定义管理所有的Route
  2. Route 配置页面与路由的关系
    1. path 就是路由地址
    2. element 导入的组件
  3. 注册二级路由 Outlet,类似于Vue中的Router-view
    1. 页面修改
    import { Outlet } from "react-router-dom";
    
    export function Cart() {
        return <div>
            <h1>汽车首页</h1>
            <Outlet></Outlet>
        </div>
    }
    
    1. 路由组件修改
    function App() {
        return (
            <div className="App">
                <Routes>
                    <Route path="/" element={<Home/>}></Route>
                    <Route path="cart" element={<Cart/>}>
                        <Route path=":id" element={<CartDetail/>}/>
                    </Route>
                </Routes>
            </div>
        )
    }
    
    1. 只是在Route内又加入了一个Route
    2. 打开我们的路由详情页http://127.0.0.1:5173/cart/123 就可以看到二级目录 image.png
    3. 如果还有三级,在二级Route中套入Route,同理二级文件中也需要加入Outlet
      1. 页面组件
      import { Outlet } from "react-router-dom";
      
      export function Cart() {
          return <div>
              <h1>汽车首页</h1>
              <Outlet></Outlet>
          </div>
      }
      
      export function CartDetail() {
          return <div>
              <h2>汽车首页详细</h2>
              <div>
                  <Outlet></Outlet>
              </div>
          </div>
      }
      
      
      export function DetailRemark() {
          return <div>
              <span>汽车详情描述</span>
          </div>
      }
      
      1. 路由文件
      import { Route, Routes } from "react-router-dom";
      import { Cart, CartDetail, DetailRemark } from "./view/cart";
      import Home from "./view/home";
      
      function App() {
          return (
              <div className="App">
                  <Routes>
                      <Route path="/" element={<Home/>}></Route>
                      <Route path="cart" element={<Cart/>}>
                          <Route path=":id" element={<CartDetail/>}>
                              <Route path="remark" element={<DetailRemark/>}/>
                          </Route>
                      </Route>
                  </Routes>
              </div>
          )
      }
      
      1. 访问三级目录http://127.0.0.1:5173/cart/123/remark image.png
      2. 访问下级路由时,默认是打开上级目录的

4. 注册404页面

  1. 创建组件
  2. 注册404页面路由
    function App() {
        return (
            <div className="App">
                <Routes>
                    <Route path="/" element={<Home/>}></Route>
                    <Route path="cart" element={<Cart/>}>
                        <Route path=":id" element={<CartDetail/>}>
                            <Route path="remark" element={<DetailRemark/>}/>
                        </Route>
                    </Route>
                    <Route path="*" element={<Page404/>}></Route>
                </Routes>
            </div>
        )
    }
    
  3. path使用了 * 星号,同时还需要把该路由放到最下面

5. 路由跳转 Link组件

import { Link, Outlet } from "react-router-dom";
export function Cart() {
    return <div>
        <h1>汽车首页</h1>
        <nav>
            <Link to="/cart/1">车辆1</Link>
            <Link to="/cart/2">车辆2</Link>
        </nav>
        <Outlet></Outlet>
    </div>
}
  1. 在页面上看不到多大变化,但是可以通过浏览器的URL看到发生了改变

6. 参数传递

  1. PathParams传参
    1. 需要修改路由的path
        <Route path=":id" element={<CartDetail/>} />
    
    1. :id 就是 我们传递的参数,还可以修改为其他名称或者传递多个
        <Route path=":name" element={<CartDetail/>} />
        <Route path=":id/:name" element={<CartDetail/>} />
    
    1. 通过Link传递参数
    <Link to="/cart/1">车辆1</Link>
    <Link to="/cart/2">车辆2</Link>
    <Link to="/cart/1/捷豹">捷豹</Link>
    
    1. 获取参数 useParams
    let params = useParams();
    
    export function CartDetail() {
        let params = useParams();
    
        return <div>
            <h2>汽车首页详细{params.id}</h2>
            <div>
                <Outlet></Outlet>
            </div>
        </div>
    }
    
    1. 通过点击不同的link 就会显示不同的页面了
  2. SearchParams 传参
    1. 修改我们的Link组件
        <Link to="/cart/1?name=捷豹&color=蓝色">车辆1</Link>
    
    1. 使用 useSearchParams Hook
    export function CartDetail() {
        let params = useParams();
        let [searchParams, setSearchParams] = useSearchParams();
    
        return <div>
            <h2>汽车首页详细{params.id}</h2>
            <div>
                searchParams 传参
                <p>{searchParams.get("name")}</p>
                <p>{searchParams.get("color")}</p>
            </div>
    
            <div>
                <Outlet></Outlet>
            </div>
        </div>
    }
    
    1. 也可以通过setSearchParams修改参数,和setStatus一样

7. 编程式导航

  1. 通过Js编程的方式进行路由跳转
  2. 使用Hook useNavigate
import { useNavigate } from "react-router-dom";

export function Cart() {
    let navigate = useNavigate();

    return <div>
        <h1>汽车首页</h1>
        <nav>
            <button onClick={()=>navigate('/cart/3')}>车辆3</button>
        </nav>
        <Outlet></Outlet>
    </div>
}
  1. 传递参数

    1. search 参数
        <button onClick={()=>navigate('/cart/4?name=特斯拉&color=白色')}>车辆4</button>
    
    1. params 参数
    <button onClick={()=>navigate('/cart/3')}>车辆3</button>
    
    1. state 参数
        navigate('/cart/4', { state: {name:'tom',age:"20"} })
    
    1. state参数获取需要使用 hook ** useLocation **
        export function CartDetail() {
        const state = useLocation()
    
        return <div>
            <h2>汽车首页详细{params.id}</h2>
            {state.state?.name}
            {state.state?.color}
        </div>
    }
    

3. 总结

  1. 通过本章学习了把单页面应用变为多页面应用,并且进行路由嵌套,路由跳转,路由传参

1. 三种不同传参的方法的区别

  1. params传参
    • 优点:刷新页面,参数不丢失
    • 缺点:1.只能传字符串,传值过多url会变得很长 2. 参数必须在路由上配置.
    • 举例::path
  2. search传参
    • 优点:刷新页面,参数不丢失
    • 缺点:只能传字符串,传值过多url会变得很长,获取参数需要使用hooks useSearchParams
    • 举例:<Link to="/cart/1?name=捷豹&color=蓝色">车辆1</Link>
  3. state传参
    • 优点:可以传对象
    • 缺点:刷新页面,参数丢失, 使用 useLocation 获取参数
    • 举例:<button onClick={() => navigate('/cart/5', { state: {name:'路虎',color:"黑色"} })}>车辆4</button>