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
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。