mini-react-router 实现核心路由跳转功能

1. 实现路由跳转

实现了与react-router-dom5.x版本相同的用法,包括BrowserRouterLinkSwitchRoute等组件,基本用法如下代码所示:

<Router>
    <div>
        <Link to="/a">组件A</Link>
        <Link to="/b">组件B</Link>
        <Link to="/a/c">组件C</Link>
    </div>
    <Switch>
        <Route path="/a" component={A} />
        <Route path="/b" component={B} />
        <Route path="/a/c" component={C} />
    </Switch>
</Router>

2. BrowserRouter

BrowserRouter组件需要将全部的组件包起来,利用context提供history对象和location对象。其中,history对象由createBrowserHistory()提供,location对象初始值是window.location

history.listen()用于监听location的变化,当其发生变化时,更新state中的location

import { createContext, useState, useEffect } from 'react';
import { createBrowserHistory } from 'history';

const history = createBrowserHistory();
export const RouterContext = createContext();

const BrowserRouter = ({ children }) => {
    const [location, setLocation] = useState(window.location);
    useEffect(() => {
        // 监听路由变化
        const unlisten = history.listen(({ location: loc }) => {
            setLocation(loc);
        });
        return () => {
            unlisten && unlisten();
        };
    }, []);
    return (
        <RouterContext.Provider value={{ history, location }}>{children}</RouterContext.Provider>
    );
};

export default BrowserRouter;

3. Link

Link组件里实际上是a链接。但点击路由时,实际上是不发生跳转的,所以在onClick事件里阻止了a链接跳转的默认行为。并且利用history.push()将当前的location推入history栈中,触发BrowserRouter中的监听器,更新state中的location。此时window.location也将更新,url会发生变化。

import { useContext } from 'react';
import { RouterContext } from './BrowserRouter';

const style = {
    border: '2px solid blue',
    padding: '10px',
    margin: '20px',
    textDecoration: 'none',
};

const Link = ({ to, children }) => {
    const { history } = useContext(RouterContext);
    return (
        <a
            href={to}
            style={style}
            onClick={e => {
                e.preventDefault();
                history.push(to);
            }}
        >
            {children}
        </a>
    );
};

export default Link;

4. Switch

Switch组件将一系列Route组件包起来。若包含多个Route组件,则children是数组;若只有一个Routechildren是单个元素,故进行判断,确保转化为数组。

statelocation.pathname与包含的Route组件path进行对比,只渲染匹配上的Route

import { useContext } from 'react';
import { RouterContext } from './BrowserRouter';

const Switch = ({ children }) => {
    const { location } = useContext(RouterContext);
    const routes = Array.isArray(children) ? children : [children];
    return (
        <>
            {routes.map(child => {
                const {
                    props: { path },
                } = child;
                if (location.pathname === path) return child;
                return null;
            })}
        </>
    );
};

export default Switch;

5. Route

statelocation.pathname与当前Routepath进行对比,若匹配上,则渲染传入的组件。

import { createElement, useContext } from 'react';
import { RouterContext } from './BrowserRouter';

const Route = ({ path, component }) => {
    const { location } = useContext(RouterContext);
    return <>{location.pathname === path ? createElement(component) : null}</>;
};

export default Route;

6. 源码

「GitHub」


以上是本人学习所得之拙见,若有不妥,欢迎指出交流!


📘📘欢迎在我的博客上访问:
https://lzxjack.top/

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

火星飞鸟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值