1.1基础使用
安装版本 "react-router-dom": "^6.3.0",
import logo from "./logo.svg";
import "./App.css";
import { BrowserRouter, Routes, Route,Link } from "react-router-dom";
const Home = () => "home";
const About = () => "这是about";
function App() {
return (
<div className="App">
<header className="App-header">
<BrowserRouter>
<Routes>
<Route index element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
<Link to="/about">About</Link>
<Link to="/">home</Link>
</BrowserRouter>
</header>
</div>
);
}
export default App;
- BrowserRouter:浏览器环境下使用,不添加会报错。
- Routes:路由的包裹
- Route:实际的路由
- Link: 跳转路由的边界线按钮 注:BrowserRouter/Routes等,只是路由规则,在界面上是看不到的,可以通过修改浏览器的地址栏看到切换效果; 想要在页面上操作路由切换用Link;
1.2 动态路由
useParams:可以拿到动态参数 path='*' 兜底的路由
<Route path='/child' >
<Route path=":invoiceId" element={<Home />} />
<Route path="sent" element={< >舒适的房间</>} />
</Route>
<Route path="*" element={< >嘟嘟嘟嘟</>} />
</Routes>
<Link to='/child/dddd'>
invoiceId
</Link>
<Link to='/child/send'>
send
</Link>
const Home = () => {
let params = useParams();
console.log('params',params)
return "home"};
1.3 深层路由
```js
<Routes>
<Route path="/users/*" element={<Users />} />
</Routes>;
// and now deeper in the tree
function Users() {
return (
<div>
<h1>Users</h1>
<Routes>
<Route path="account" element={<Account />} />
</Routes>
</div>
);
}
```js
1.4 配合懒加载使用
const About = React.lazy(() => import("./pages/About"));
<Route
path="about"
element={
<React.Suspense fallback={<>...</>}>
<About />
</React.Suspense>
}
/>
1.5 方法跳转
const Home = () => {
let params = useParams();
const mavigate = useNavigate();
console.log('params',params)
return <div>''home
<button onClick={() => {
mavigate('/about')
}}>跳转到about</button>
</div>
};
2.1 withRouter 为什么没了
withRouter 是将history, location, match就会被放进这个组件的props,往下传递。 v6的版本更希望通过hook实现这些功能(useParams,useLocation等)
2.2 V6中只支持 <Route element>
参考React 中Suspense的用法,<Suspense fallback={<Spinner />}>,传入的是React 元素,而非组件,可以将props更容易的传入到对应的元素内(社区推荐)
1. 可以隐式的传递props到元素内
1. V6以下形式的包版本体积过大
2.3为什么取消正则路由
- 正则路由为V6版本的路由排序带来很多问题,比如,如果定义一个正则的优先级?
- 正则路由占据了React Router近1/3的体积
- v6通过枚举解决正则的问题
3.实现一个React-router
import logo from "./logo.svg";
import "./App.css";
import { useEffect, useState,createContext } from "react";
const RouterContext = createContext(); // path改变
const HistoryContext = createContext(); // 子组件可以订阅方法
const BrowserRoute =(props) => {
const [path,setPath] = useState(window.location.pathname || '/'); //首次渲染
useEffect(() => {
window.addEventListener('popstate',handleFun)
return () => {
window.removeEventListener('popstate',handleFun)
}
},[])
const handleFun =() => {
let {pathname} = window.location;
console.log('-----')
setPath(pathname);
}
const push =(path) => {
setPath(path); // path 发生改变让界面发生变化
window.history.replaceState({path},null,path); // 并不会变化
}
const go =() => {
window.history.go(-1);
}
return (
<RouterContext.Provider value={path}>
<HistoryContext.Provider value={{push,go}}> //子组件订阅方法
{props.children}
</HistoryContext.Provider>
</RouterContext.Provider>
)
}
const Route =(props) => {
const {component,path:pathName} = props;
return (<RouterContext.Consumer> //订阅path
{(path) => {
console.log('----',path)
return pathName === path?component:null;
}}
</RouterContext.Consumer>)
}
function App() {
return (
<div className="App">
<header className="App-header">
<BrowserRoute>
<Route path='/' component={<div>saf</div>}></Route>
<Route path='/about' component={<div>about</div>}></Route>
<Route path='/home' component={<div>home</div>}></Route>
</BrowserRoute>
</header>
</div>
);
}
export default App;
问题:history.pushState 不会引起界面变化,此类事件只在点击前进后退按钮才生效, 因此,React Router使用history对象来监听事件的变化(pop,push)
let history = createBrowserHistory();
history.listen(({ location, action }) => {
// this is called whenever new locations come in
// the action is POP, PUSH, or REPLACE
});