import React, { useState } from 'react';
import { BrowserRouter, Link, Route, Switch, Redirect } from 'react-router-dom';

const ProductList = (props: any) => {
    const [list, setList] = useState([1, 2, 3, 4]);
    const toDetail = (item: any) => {
        props.history.push(`/detail/${item}`);
    };
    return <div>
        {list.map((item: any) => {
            return <div key={item} onClick={() => toDetail(item)}>{item}</div>;
        })}
    </div>;
};

const Detail = ({match, history, location}: any) => {
    const {id} = match.params;
    console.log(history, location); // location可以传很多参数

    return <div>
        <div>详情{id}</div>
        <button onClick={history.goBack}>后退</button>
    </div>;
};

const ProductMgt = () => {
    return <div>
        商品管理
        <nav>
            <Link to="delete">删除</Link>
            <Link to="/management/add">添加</Link>
        </nav>
        {/*嵌套路由*/}
        <Switch>
            <Route path="/management/delete" component={() => <div>删除</div>}/>
            <Route path="/management/add" component={() => <div>添加</div>}/>
            <Redirect to="/management/add"/>
        </Switch>
    </div>;
};

function PrivateRoute({component: Component, isLogin, ...rest}: any) {

    return <Route {...rest} render={
        (props: any) => isLogin ? (<Component/>) : (<Redirect to={{
            pathname: '/login',
            state: {redirect: props.location.pathname}
        }}
        />)}
    />;
}

const IndexView = () => {
    // BrowserRouter 和provider作用相同都是为了传参
    return <BrowserRouter>
        <nav>
            <Link to="/">商品列表</Link>
            <Link to="/management">商品管理</Link>
        </nav>
        {/*switch独占,只要匹配到就往下不走了*/}
        <Switch>
            <Route exact={true} path="/" component={ProductList}/>
            <PrivateRoute path="/management" component={ProductMgt} isLogin={true}/>
            <Route path="/detail/:id" component={Detail}/>
            <Route path="/login" component={() => <div>登录页面</div>}/>
            <Route component={() => <div>404</div>}/>
        </Switch>
    </BrowserRouter>;
};

export default IndexView;

原理

// history location match
import React, { useState, useEffect } from 'react';
import { createBrowserHistory } from 'history';

const RouterContext = React.createContext<any>({});

function BrowserRouter(props: any) {
    const history = createBrowserHistory(props);
    const [location, setLocation] = useState(history);


    useEffect(() => {
        const unlisten = history.listen((location: any) => {
            setLocation(location);
        });

        return () => {
            !!unlisten && unlisten();
        };
    }, []);
    return <RouterContext.Provider value={{history, location}}>
        {props.children}
    </RouterContext.Provider>;
}

function Route(props: any) {
    return <RouterContext.Consumer>
        {
            (context: any) => {
                const location = context.location;
                // @ts-ignore
                const match = matchPath(location.pathname, props);
                const myProps = {...context, match};
                let {children, component, render} = props;
                if (typeof children==='function') {
                    children = children(props);
                }
                return <RouterContext.Provider value={myProps}>
                    {
                        // children > component > render
                        children
                            ? children
                            : myProps.match  // 后面的component和render必须匹配
                            ? component // 若匹配先查找compontent
                                ? React.createElement(component)
                                : render
                                    ? render(props)
                                    : null
                            : null
                    }
                </RouterContext.Provider>;
            }
        }
    </RouterContext.Consumer>;
}

系列

重学react——slot
重学react——state和生命周期
重学react——redux
重学react——hooks以及原理
重学react——context/reducer
重学react——router
重学react——高阶组件
build your own react
React——fiber


lihaixing
463 声望719 粉丝

前端就爱瞎折腾