react-router-dom原理探究

467 阅读1分钟
// 原生原理
window.addEventListener("hashchange", () => {});

function push(path) {
    history.pushState({
        title: "",
        path: path
    });
}
// 监听浏览器事件
window.addEventListener("popstate", e => {
    console.log(e);
});

function app() {
    return (
        <div>
            <div>
                <Link to="/home" />
            </div>
            <Router>
                <Switch>
                    <Route path="" component={} />
                </Switch>
            </Router>
        </div>
    );
}

const {Provider, Consumer} = React.createContext();

// 手写
const HashRouter = (props) => {
    const {path, component, children} = props;
    const router = {
        location: {
            pathname: window.location.hash.slice(1) || ""
        },
        history: {
            push(to){
                window.location.hash = to;
            }
        },
        match: {
            params: {}
        }
    };

    window.addEventListener("hashchange", ()=>{
        // 修改路由
    });

    window.location.hash = window.location.hash || "/";

    return (
        <Provider value={router}>
            {children}
        </Provider>
    );
}

const Route = (props) => {
    const {path, Component, exact= false} = props;
    return (
        <Consumer>
            {router => {
                const {location} = router;
                // 通过正则匹配,可用path-to-regexp插件
                if(path === location.pathname){
                    return <Component {...props}/>
                }
                return null;
            }}
        </Consumer>
    );
}

const Link = (props) => {
    const {to} = props;
    return (
        <Consumer>
            {state => {
                return <a onClick={()=>{
                    state.history.push(to);
                }} >
                    {this.props.children}
                </a>
            }}
        </Consumer>
    );
}

const Redirect = (props) => {
    const {to} = props;
    return (
        <Consumer>
            {state => {
                state.history.push(to);
                return null;
            }}
        </Consumer>
    );
}
// 匹配一个Route
const Switch = (props) => {
    const {children} = props;
    return (
        <Consumer>
            {state => {
                const pathname = state.location.pathname;
                children.forEach(item => {
                    // regex 为 item.props.path 的正则表达式
                    if(regex.test(pathname)){
                        return item;
                    }
                });
                return null;
            }}
        </Consumer>
    );
}