React18路由V6,Navigate导航,嵌套路由<Outlet />,封装高阶组件,实现在类组件中使用useNavigate()

956 阅读2分钟

URL的hash

  • 前端路由是如何做到URL和组件内容进行映射呢?监听URL的改变
  • URL的hash,即锚点(#),本质上是改变window.location的href属性
  • 可以通过直接赋值location.hash来改变href,但是页面不发生更新

image.png

image.png

H5的History

image.png

认识React-Router

  • React Router6.X版本较之前发生了较大变化
  • 目前React Router6.X 已经非常稳定,可放心食用 安装React Router

npm i react-router-dom

Router的基本使用

image.png

路由映射

image.png

路由配置和跳转

image.png

NavLink的使用

image.png

image.png

image.png

代码 :

import React, { PureComponent } from "react";
import { NavLink, Route, Routes } from "react-router-dom";
import Home from "./pages/Home";
import About from "./pages/About";
import "./style.css";

export class App extends PureComponent {
  render() {
    return (
      <div className="app">
        <div className="header">
          <span>Header</span>
          <div className="nav">
            {/* <Link to="/home">首页</Link> */}
            {/* <Link to="/about">关于</Link> */}
            {/* <NavLink to="/home" style={({ isActive }) => ({ color: isActive ? "red" : "" })}>
              首页
            </NavLink>
            <NavLink to="/about" style={({ isActive }) => ({ color: isActive ? "red" : "" })}>
              关于
            </NavLink> */}
            <NavLink to="/home" className={({ isActive }) => (isActive ? "zmClass" : "")}>
              首页
            </NavLink>
            <NavLink to="/about" className={({ isActive }) => (isActive ? "zmClass" : "")}>
              关于
            </NavLink>
          </div>
        </div>
        <div className="content">
          {/* 映射关系:path => Component */}
          <Routes>
            <Route path="/home" element={<Home />}></Route>
            <Route path="/about" element={<About />}></Route>
          </Routes>
        </div>
        <div className="footer">Footer</div>
      </div>
    );
  }
}
export default App;
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import { HashRouter } from "react-router-dom";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <React.StrictMode>
    <HashRouter>
      <App />
    </HashRouter>
  </React.StrictMode>
);
                                          自定义样式
.zmClass {
  color: aqua;
  font-size: 20px;
}

Navigate导航

  • Navigate组件被渲染就会跳转到相应的组件页面
import React, { PureComponent } from "react";
import { Navigate } from "react-router-dom";
export class Login extends PureComponent {
  constructor() {
    super();
    this.state = {
      isLogin: false,
    };
  }
  login() {
    this.setState({
      isLogin: true,
    });
  }
  render() {
    const { isLogin } = this.state;
    return (
      <div>
        <h1>Login Pages</h1>
        {/* 只要出现Navigate页面就会跳转 */}
        {!isLogin ? <button onClick={(e) => this.login()}>登录</button> : <Navigate to="/home" />}
      </div>
    );
  }
}
export default Login;
  • /重定向<Route path="/" element={<Navigate to="/home" />}></Route>
import React, { PureComponent } from "react";
import { NavLink, Navigate, Route, Routes } from "react-router-dom";
import Home from "./pages/Home";
import About from "./pages/About";
import "./style.css";
import Login from "./pages/Login";
export class App extends PureComponent {
  render() {
    return (
      <div className="app">
        <div className="header">
          <span>Header</span>
          <div className="nav">
            <NavLink to="/home" className={({ isActive }) => (isActive ? "zmClass" : "")}>
              首页
            </NavLink>
            <NavLink to="/about" className={({ isActive }) => (isActive ? "zmClass" : "")}>
              关于
            </NavLink>
            <NavLink to="/login" className={({ isActive }) => (isActive ? "zmClass" : "")}>
              登录
            </NavLink>
          </div>
        </div>
        <div className="content">
          {/* 映射关系:path => Component */}
          <Routes>
            <Route path="/" element={<Navigate to="/home" />}></Route>
            <Route path="/home" element={<Home />}></Route>
            <Route path="/about" element={<About />}></Route>
            <Route path="/login" element={<Login />}></Route>
          </Routes>
        </div>
        <div className="footer">Footer</div>
      </div>
    );
  }
}
export default App;

NotFound页面配置

        <div className="content">
          {/* 映射关系:path => Component */}
          <Routes>
            <Route path="/" element={<Navigate to="/home" />}></Route>
            <Route path="/home" element={<Home />}></Route>
            <Route path="/about" element={<About />}></Route>
            <Route path="/login" element={<Login />}></Route>
            <Route path="*" element={<NotFound />}></Route>
          </Routes>
        </div>

嵌套路由

          <Routes>
            <Route path="/" element={<Navigate to="/home" />}></Route>
            <Route path="/home" element={<Home />}>
              {/* 嵌套路由 */}
              {/* 匹配到/home需要重定向到二级路由,显示内容 */}
              <Route path="/home" element={<HomeRecommend />}></Route>
              <Route path="/home/recommend" element={<HomeRecommend />}></Route>
              <Route path="/home/ranking" element={<HomeRanking />}></Route>
            </Route>
            <Route path="/about" element={<About />}></Route>
            <Route path="/login" element={<Login />}></Route>
            <Route path="*" element={<NotFound />}></Route>
          </Routes>

配置二级路由出口 <Outlet />

import React, { PureComponent } from "react";
import { Link, Outlet } from "react-router-dom";
export class Home extends PureComponent {
  render() {
    return (
      <div>
        <h2>Home Pages</h2>
        <div className="home-nav">
          <Link to="/home/recommend">推荐</Link>
          <Link to="/home/ranking">排行榜</Link>
        </div>
        <div>
          {/* 占位的组件,类似router-view */}
          <Outlet />
        </div>
      </div>
    );
  }
}
export default Home;

自定义(手动)跳转-useNavigate()

函数式组件

import React from "react";
import { NavLink, Navigate, Route, Routes, useNavigate } from "react-router-dom";
import Home from "./pages/Home";
import About from "./pages/About";
import "./style.css";
import Login from "./pages/Login";
import NotFound from "./pages/NotFound";
import HomeRecommend from "./pages/HomeRecommend";
import HomeRanking from "./pages/HomeRanking";
import Category from "./pages/Category";
import Order from "./pages/Order";

export function App() {
  // hooks放置到顶层
  const navigate = useNavigate();
  function navigateTo(path) {
    navigate(path);
  }
  return (
    <div className="app">
      <div className="header">
        <span>Header</span>
        <div className="nav">
          <NavLink to="/home" className={({ isActive }) => (isActive ? "zmClass" : "")}>
            首页
          </NavLink>
          <NavLink to="/about" className={({ isActive }) => (isActive ? "zmClass" : "")}>
            关于
          </NavLink>
          <NavLink to="/login" className={({ isActive }) => (isActive ? "zmClass" : "")}>
            登录
          </NavLink>
          <button onClick={(e) => navigateTo("/order")}>订单</button>
          <button onClick={(e) => navigateTo("/category")}>分类</button>
        </div>
      </div>
      <div className="content">
        {/* 映射关系:path => Component */}
        <Routes>
          <Route path="/" element={<Navigate to="/home" />}></Route>
          <Route path="/home" element={<Home />}>
            {/* 嵌套路由 */}
            <Route path="/home" element={<HomeRecommend />}></Route>
            <Route path="/home/recommend" element={<HomeRecommend />}></Route>
            <Route path="/home/ranking" element={<HomeRanking />}></Route>
          </Route>
          <Route path="/about" element={<About />}></Route>
          <Route path="/login" element={<Login />}></Route>
          <Route path="/category" element={<Category />}></Route>
          <Route path="/order" element={<Order />}></Route>
          <Route path="*" element={<NotFound />}></Route>
        </Routes>
      </div>
      <div className="footer">Footer</div>
    </div>
  );
}
export default App;

封装高阶组件,实现在类组件中使用useNavigate()

import { useNavigate } from "react-router-dom";
function withRouter(OriginCpn) {
  return (props) => {
    const navigate = useNavigate();
    const router = { navigate };
    return <OriginCpn {...props} router={router} />;
  };
}
export default withRouter;
import React, { PureComponent } from "react";
import { NavLink, Navigate, Route, Routes } from "react-router-dom";
import Home from "./pages/Home";
import About from "./pages/About";
import "./style.css";
import Login from "./pages/Login";
import NotFound from "./pages/NotFound";
import HomeRecommend from "./pages/HomeRecommend";
import HomeRanking from "./pages/HomeRanking";
import withRouter from "./hoc/with_router";
import Category from "./pages/Category";
import Order from "./pages/Order";

export class App extends PureComponent {
  navigateTo(path) {
    console.log("path=> ", path);
    // 类组件中使用useNavigate()跳转,报错
    const { navigate } = this.props.router;
    console.log("666=> ");
    navigate(path);
  }
  render() {
    return (
      <div className="app">
        <div className="header">
          <span>Header</span>
          <div className="nav">
            <NavLink to="/home" className={({ isActive }) => (isActive ? "zmClass" : "")}>
              首页
            </NavLink>
            <NavLink to="/about" className={({ isActive }) => (isActive ? "zmClass" : "")}>
              关于
            </NavLink>
            <NavLink to="/login" className={({ isActive }) => (isActive ? "zmClass" : "")}>
              登录
            </NavLink>
            <button onClick={(e) => this.navigateTo("/order")}>订单</button>
            <button onClick={(e) => this.navigateTo("/category")}>分类</button>
          </div>
        </div>
        <div className="content">
          {/* 映射关系:path => Component */}
          <Routes>
            <Route path="/" element={<Navigate to="/home" />}></Route>
            <Route path="/home" element={<Home />}>
              {/* 嵌套路由 */}
              <Route path="/home" element={<HomeRecommend />}></Route>
              <Route path="/home/recommend" element={<HomeRecommend />}></Route>
              <Route path="/home/ranking" element={<HomeRanking />}></Route>
            </Route>
            <Route path="/about" element={<About />}></Route>
            <Route path="/login" element={<Login />}></Route>

            <Route path="/category" element={<Category />}></Route>
            <Route path="/order" element={<Order />}></Route>
            <Route path="*" element={<NotFound />}></Route>
          </Routes>
        </div>
        <div className="footer">Footer</div>
      </div>
    );
  }
}
export default withRouter(App);