用到的插件
react-router-dom的理解
1.react的一个插件库。 2.专门用来实现一个SPA应用。
import {
HashRouter,
BrowserRouter,
Link,
NavLink,
Route,
Switch,
Redirect,
} from "react-router-dom";
HashRouter, BrowserRouter
这两个是设置哈希模式,与history模式,需要套在最外层的标签
当时history的时候刷新会出现404,所以需要在webpack里面配置
设置:
historyApiFallback: {
// Paths with dots should still use the history fallback.
// See https://github.com/facebook/create-react-app/issues/387.
disableDotRule: true,
//index: paths.publicUrlOrPath,
},
Route相当于router-view 用来根据地址栏匹配显示对应的组件
path 匹配的路径
component 是要渲染的组件 并且将路由对象映射到props
组件标签中渲染的路由组件 默认不会注入路由对象
exact 精准匹配只有path和路径完全匹配才会渲染,注意在有嵌套路由的地方不要精准匹配
switch 万里挑一 只返回第一个匹配到的元素
redirect 重定向注意死循环
<Switch>
<Redirect exact from="/" to="/home"></Redirect>
//重定向,注意前面要加精准匹配,exact,防止死循环
<Route path="/my">
<My></My> //这样写没办法传参
</Route>
//下面是嵌套路由,注意不要写精准匹配
<Route path="/user" component={() => {
return(<div>
{/* <h2>这里是user</h2> */}
<User></User>
<NavLink to="/user/info">用户信息</NavLink>
<NavLink to="/user/login">用户登录</NavLink>
<hr />
<Route path="/user/info" component={UserInfo}></Route>
<Route path="/user/login" component={UserLogin}></Route>
</div>)
}}></Route>
<Route path="/home/:id/:ps" component={Home}></Route>//动态路由传参
<Route path="/home" component={Home}></Route>
{/* 嵌套路由 */}
{/* 404 */}
{ <Route component={NotFound}></Route>} //路径都不对的时候,跳404,写在最后面,不用写path
</Switch>
路由传参的方法
1.params参数
路由链接(携带参数):<Link to='/demo/test/tom/18'}>详情</Link>
注册路由(声明接收):<Route path="/demo/test/:name/:age" component={Test}/>
接收参数:this.props.match.params
2.search参数
路由链接(携带参数):<Link to='/demo/test?name=tom&age=18'}>详情</Link>
注册路由(无需声明,正常注册即可):<Route path="/demo/test" component={Test}/>
接收参数:this.props.location.search
备注:获取到的search是urlencoded编码字符串,需要借助querystring解析
3.state参数
路由链接(携带参数):<Link to={{pathname:'/demo/test',state:{name:'tom',age:18}}}>详情</Link>
history.push("/home", { us: 123, ps: 123 });
注意:正经通过state传参刷新后值不会丢
<NavLink to={{pathname:"/my",hehe:{name:'hehe'}}} activeClassName={styles.red}>
//这里用hehe代替state就可以了
withRouter
也是一个高阶组件 从context 获取路由对象 映射到组件的props,如果在你想在一般组件使用 路由组件所特有的API 时, 就要借助 withRouter withRouter可以加工一般组件, 让一般组件具备路由组件所特有的API,存在这个组件的this.props.history,就是为了把普通组件转换成路由组件,withRouter 提供给组件路由对象 只有在BrowserRouter 和 hashRouter内部的才可以使用
普通组件与路由组件
路由组件与一般组件props接收的数据对比图:
路由组件与一般组件的不同之处
1.写法不同:
一般组件: <Demo/>
路由组件: <Route path="/demo" component={Demo}/>
2.存放位置不同:
一般组件: components
路由组件: pages
3.接收到的props不同:
一般组件: 写组件标签时传递了什么,就能收到什么
路由组件: 接收带三个固定的属性
history:
go: ƒ go(n)
goBack: ƒ goBack()
goForward: ƒ goForward()
push: ƒ push(path, state)
replace: ƒ replace(path, state)
location:
pathname: "/home"
search: ""
state: undefined
match:
params: {}
path: "/home"
url: "/home"
渲染路由组件的方式
componet props里直接有路由对象 函数组件和类组件都一样
const Home = (props) => {
return <div>这里是home</div>;
//在这里直接可以通过props接收跳转的参数
};
<Route path="/home" component={Home}></Route>
直接写组件名字渲染slot
slot props没有路由对象 函数组件可以通过hooks获取 类组件 withrouter获取
import {useHistory, useLocation,useParams,useRouteMatch,} from "react-router-dom";
函数组件
const Home = (props) => {
console.log(props);
const history = useHistory();
const location = useLocation();
const params = useParams();
const routeMatch = useRouteMatch();//通过这四个参数传路由对象
console.log("history", history);
console.log("location", location);
console.log("params", params);
console.log("routeMatch", routeMatch);
return <div>这里是home</div>;
};
<Route path="/home">
<Home></Home>
</Route>
render
render不能跟组件 只能跟函数 在函数里返回组件 函数可以将props传递给组件
例如
函数组件
//这是一个函数组件
const Home = (props) => {
console.log(props);
return <div>这里是home</div>;
};
<Route path="/home" render={(props) => {
return <Home {...props}></Home>; }}>
</Route> //这样传参也行
//但是里面不能用hooks那四个函数
const Home = (props) => {
console.log(props);
return <div>这里是home</div>;
};
//或者
<Route path="/home" render={Home}></Route>
类组件
import React, { Component } from "react";
class HomeClass extends Component {
state = {};
render() {
return <div>app组件</div>;
}
componentDidMount() {
console.log(this)
}
}
export default HomeClass;
//类组件进行传参
<Route path="/home" render={(props) => {
return <HomeClass {...props}></HomeClass>
}}>
</Route> //是一样的
chilren
render不能跟组件 只能跟函数 在函数里返回组件 函数可以将props传递给组件,不管是否匹配都会显示
例如:
<Route path="/h" render={(props) => {
return <HomeClass {...props}></HomeClass>
}}></Route>
<Route path="/home" children={(props) => {
return<Home></Home>
}}></Route>
//当你地址不论是什么children渲染的组件都会出来,上面这个例子,在你用http://localhost:3000/h
这时候,HomeClass 组件与Home都会渲染出来
//拿children渲染的组件参数的时候上面return的是slot样式,所以用hooks的方法
<Route path="/home/1/2/2/3/" children={(props) => { //不管path写什么都会跳转
return<Home {...props}></Home>
}}></Route> //这个就直接能拿到props
//类组件也是通过传递props,通过withrouter获取
<Route path="/home" children={(props) => {
return<HomeClass {...props}></HomeClass>
}}></Route>
当你路由是h与children渲染组件的路由不匹配,但是也会渲染
函数组件自己封装Router
例子:做一个路由拦截,在redux里面并没有路由守卫钩子函数
先封装一个组件,把要跳转的path路径传递到组件里面,组件拿到传递过来的path进行router,从而来进行路由拦截
AuthComponent.js
知识点: const { path, children } = props //注意这里需要从props里面取path,在index会用,
import React, { useContext } from "react";
import { Route, Redirect, useLocation } from "react-router-dom";
import userContext from "./userContext";
function AuthComponent(props) {
const user = useContext(userContext);
const location = useLocation()
console.log("location", location)
console.log(user);
const { path, children } = props //注意这里需要从props里面取path,在index会用,
return (
<div>
<Route path={path}> //从这里把path传递出去
{user.user ? ( //下面的三元是判断user是否是真,若是真就不拦截,是假就重定向
children
) : (
<Redirect
to={{
pathname: "/login",
state: { from: location },
}}
/>
)}
</Route>
</div>
);
}
export default AuthComponent;
在index用的时候,不在用router,而是用自己封装的
<Switch>
<Route path="/public">
<PublicPage />
</Route>
<Route path="/login">
<LoginPage />
</Route>
<AuthComponent path={"/protected"}> //这里就能传递到组件内部了,在组件里面进行props进行获取就行 也可以path="/protected" 这样传
<ProtectedPage /> //这里就是插槽
</AuthComponent>
</Switch>