react-router
react-router-dom概念
react-router-dom是一个管理前端路由的第三方库,为什么会出现前端路由这个概念,也是为了让用户体验升级,通过不刷新页面就可以完成页面之间的切换,甚至能达到原生app的效果,这算前端的最高级体验。
第二点,因为所有的页面都在同一个应用里面,页面相互之间的切换不需要再进行 url请求、js,css解析、dom渲染等,这样大大减少了这些步骤所消耗的性能。
列举react-router的几个组件
- BrowserRouter
- Router
- Link
- Switch
- useHistory
- useRouteMatch
- useLocation
- useParams
- withRouter
依次来进行解析
BrowserRouter
import { createBrowserHistory } from 'history'
<Router history = { this.history } children={ this.props.children } />
Router 创建context,传递history
<RouterContext.Provider
value = {{
history: this.props.history,
location: this.state.location,
match: 初始化一个match
}}
>
{ this.props.children }
</RouterContext.Provider>
constructor(){
this.props.history.listen((location) => {
this.setState({state})
})
}
Link 渲染成a 标签 ,需要禁止 默认行为
hanldeClick = event => {
event.preventDefault()
this.context.history.push( this.props.to )
}
render(){
<a href = { to } {...resProps} onClick = { this.handleClick }>
{ children }
</a>
}
Route 重头戏 可以接受三个方式 children component render 三者之间是互斥关系,加载顺序如下: children > component > render 大概使用方式如下:
<Route
path = "/"
children={children}
component = { HomePage }
render = { render }
/>
//接下来就是代码实现
<RouterContext.Consumer>
{
context => {
const { history,location } = context
const { children, component,render,path, computedMatch } = this.props;
const match =
computedMatch ? computedMatch
: path ? matchPath(location.pathname,this.props) : context.match
const props = { ...context,match }
// match children, component, render, null
// 不match children(function), null
return (
<RouterContext.Provider value={ props }>
match ?
children ? typeof children === "function" ? children(props): children
: component ? React.createElement(component,props)
: render ? render(props) : null
: typeof children === "function" ? children(props): null
</RouterContext.Provider>
)
}
}
</RouterContext.Consumer>
敲重点 为什么要在return里面包一层 RouterContext.Provider
因为context会采取就近原则 会从 最上面获取match location location因为setState还变了一下, match是没有变
所以需要在match变化之后需要重新包一层 RouterContext.Provider 因为context value变化 子组件重新渲染更新
所以当子组件变化之后 嵌套路由里面所有的值 取得就是最新的值
Switch 独占路由 : 从上往下匹配,如果匹配到了就默认终止匹配
<RouterContext.Consumer>
{
context => {
let match,element;
let { location } = context
React.Children.forEach(this.props.children, child => {
//只要匹配上 match就不等于null 独占路由了
if(match == null && React.isValidElement(child)){
element = child;
match = child.props.path ? matchPath(location.pathname,child.props) : context.match
}
})
return match ? React.cloneElement(element,{ computedMath:match }) : null
}
}
</RouterContext.Consumer>
Redirect 跳转
<RouterContext.Consumer>
{
context => {
let { location,history,match } = context
let { push=false,to } = this.props
return <Lifecycle onMount={ ()=> { push ? history.push(to) : history.replace(to) } } ></Lifecycle>
}
}
</RouterContext.Consumer>
class Lifecycle extends Component{
componentDidMount() {
this.props.onMount.call(this)
}
render(){
return null
}
}
高阶组件 withRouter
const withRouter = WrappedComponent => props => {
return (
<RouterContext.Consumer>
{
context => {
return <WrappedComponent { ...props } { ...context } />
}
}
</RouterContext.Consumer>
)
}
自定义hooks
useRouteMatch,useHistory,useParams,useLocation
const function useRouterMatch(){
return useContext(RouterContext).match
}
const function useHistory(){
return useContext(RouterContext).history
}
const function useParams(){
return useRouterMatch().params ? useRouterMatch().params : {}
}
const function useLocation(){
return useContext(RouterContext).location
}
好了以上就是react-router相关的组件