Skip to content

ReactRouter

浏览器的两种页面跳转方式

安装

npm install react-router-dom

ReactRouter的基本使用

路由配置和跳转

这里假设登录界面有一个isLogin字段,如果为ture则自动跳转到首页,否则则显示登录文字

示例代码:

jsx
import React, {Component} from 'react';
import {Navigate} from "react-router-dom";

class Login extends Component {
    constructor() {
        super();
        this.state = {
            isLogin: false
        }
    }

    login() {
        this.setState({isLogin: true});
    }

    render() {
        const {isLogin} = this.state;
        const element = isLogin ? <Navigate to="/"/> : <button onClick={() => {
            this.login()
        }}>登录</button>
        return (
            <div>
                <h2>登录页面</h2>
                {element}
            </div>
        );
    }
}

Login.propTypes = {};

export default Login;

Navigate其中一个应用:

这样匹配/可以重定向到/home路由

jsx
   <Routes>
        <Route path='/' element={<Navigate to="/home"/>}/>
        <Route path='/home' element={<Home/>}/>
    </Routes>

NotFound

嵌套路由

路由跳转

官方推荐使用useNavigate,但是useNavigate只能用于函数式组件中

示例代码:

jsx
import { Route, Routes, useNavigate} from "react-router-dom";
import Home from "./pages/Home";
import About from "./pages/About";
import Profile from "./pages/Profile";
import classNames from "classnames";
import Login from "./pages/Login";
import NotFound from "./pages/NotFound";
import HomeRecomend from "./pages/HomeRecomend";

function App() {
    // hooks只能放在最上面
    const navigate = useNavigate()

    function navigateTo(url) {
        navigate(url)
    }

    return (
        <div className="App">
            <div style={{display: "flex", justifyContent: "space-around"}}>
                <button onClick={() => { navigateTo("/profile") }}>点击跳转我的</button>
            </div>
            <Routes>
                <Route path='/' element={<Navigate to="/home"/>}/>
                <Route path='/profile' element={<Profile/>}/>
            </Routes>
        </div>
    );
}

export default App;

类组件如果想要使用navigate对象,可以封装一个高阶函数对其扩展

示例代码:

src/hoc/withRouter.jsx

jsx
import {useNavigate} from "react-router-dom";

export default function withRouter(WrapperComponent) {
    return props => {
        const navigate = useNavigate();

        return <WrapperComponent {...props} router={navigate}/>;
    }
}

页面中使用: Profile.jsx

jsx
import React, {Component} from 'react';
import withRouter from "../hoc/withRouter";

class Profile extends Component {
    render() {
        return (
            <div>
                <h2>profile</h2>

                <button onClick={ () => { this.props.router('/home') } }>点击跳转首页</button>
            </div>
        );
    }
}

Profile.propTypes = {};

export default withRouter(Profile);

路由传参

动态路由传递参数

路由配置

jsx
<Routes>
    <Route path='/profile/:id' element={<Profile/>}/>
</Routes>

跳转方式

jsx
<NavLink to="/profile/123">我的</NavLink>
jsx
function navigateTo(url) {
    navigate(url)
}

<button onClick={ () => { navigateTo("/profile/4" ) } }>点击跳转我的</button>

如何获取参数,可以利用useParams hooks 获取路由参数

扩展withRouter,传入useParams

src/hoc/withRouter.jsx

jsx
import {useNavigate, useParams} from "react-router-dom";

export default function withRouter(WrapperComponent) {
    return props => {
        const navigate = useNavigate();
        const params = useParams();
        const router = { navigate,params }

        return <WrapperComponent {...props} router={router}/>;
    }
}

页面中获取参数

jsx
import React, {Component} from 'react';
import withRouter from "../hoc/withRouter";

class Profile extends Component {
    render() {
        return (
            <div>
                <h2>profile</h2>

                <button onClick={ () => { this.props.router.navigate('/home') } }>点击跳转首页</button>

                <h2>当前参数:</h2>
                <div> { JSON.stringify(this.props.router) } </div>
            </div>
        );
    }
}

export default withRouter(Profile);

地址栏参数

跳转

jsx
<NavLink to="/about?name=zhangsan&age=18" className={getActiveClass}>关于</NavLink>

如何获取参数,扩展withRouter

jsx
import {useNavigate, useParams, useSearchParams} from "react-router-dom";

export default function withRouter(WrapperComponent) {
    return props => {
        const navigate = useNavigate();
        const params = useParams();
        const [searchParams] = useSearchParams()
        // 将URLSearchParams转化为一个普通对象
        const query = Object.fromEntries(searchParams)
        const router = { navigate,params,query }

        return <WrapperComponent {...props} router={router}/>;
    }
}

获取参数 About.js

jsx
import React, {Component} from 'react';
import withRouter from "../hoc/withRouter";

class About extends Component {
    render() {
        return (
            <div>
                <h2>About</h2>
                <h2>当前参数:</h2>
                <div> {JSON.stringify(this.props.router)} </div>

            </div>
        );
    }
}

export default withRouter(About);

路由的配置文件

src/router/index.js

js
import {Navigate} from "react-router-dom";

import Home from "../pages/Home";
import HomeRecomend from "../pages/HomeRecomend";
import About from "../pages/About";
import Profile from "../pages/Profile";
import Login from "../pages/Login";
import NotFound from "../pages/NotFound";

export const routes = [
    {
        path: "/",
        element: <Navigate to="/home"/>
    },
    {
        path: "/home",
        element: <Home/>,
        children: [
            {
                path: "/home",
                element: <Navigate to="/home/recomend"/>
            },
            {
                path: "/home/recomend",
                element: <HomeRecomend/>
            }
        ]
    },
    {
        path: "/about",
        element: <About/>
    },
    {
        path: "/profile/:id",
        element: <Profile/>
    },
    {
        path: "/login",
        element: <Login/>
    },
    {
        path: "*",
        element: <NotFound/>
    }
]

App.js

jsx
import {useRoutes} from "react-router-dom";
import {routes} from "./router";

function App() {
    return (
        <div className="App">
            <div>
                { useRoutes(routes) }
            </div>

            {/* 以下代码可以省略 */}
            {/*<Routes>*/}
            {/*    <Route path='/' element={<Navigate to="/home"/>}/>*/}
            {/*    <Route path='/home' element={<Home/>}>*/}
            {/*        <Route path="/home" element={<Navigate to="/home/recomend"/>}></Route>*/}
            {/*        <Route path="/home/recomend" element={<HomeRecomend/>}></Route>*/}
            {/*    </Route>*/}
            {/*    <Route path='/about' element={<About/>}/>*/}
            {/*    <Route path='/profile/:id' element={<Profile/>}/>*/}
            {/*    <Route path='/login' element={<Login/>}/>*/}
            {/*    <Route path="*" element={<NotFound/>}></Route>*/}
            {/*</Routes>*/}
        </div>
    );
}

export default App;

路由懒加载

现在的配置最终经过Webpack打包后只会形成一个main.js文件,对其分包(懒加载)以后就可以形成单个js文件,分包后会形成多个xxxx.chunk.js文件

src/router/index.js

js
import NotFound from "../pages/NotFound";
import React from "react";

const About = React.lazy(() => import("../pages/About"));
const Login = React.lazy(() => import("../pages/Login"));

export const routes = [
    {
        path: "/about",
        element: <About/>
    },
    {
        path: "/login",
        element: <Login/>
    },
    {
        path: "*",
        element: <NotFound/>
    }
]

要使用懒加载项目入口js需要使用Suspense组件进行包裹

jsx
import React, {Suspense} from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import {HashRouter} from "react-router-dom";

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
    <React.StrictMode>
        <Suspense fallback={ <div>loading</div> }>
            <HashRouter>
                <App/>
            </HashRouter>
        </Suspense>
    </React.StrictMode>
);

上次更新于: