React路由渲染方式
月光晒了很凉快 人气:01. 路由的三种渲染方式
1.1 component渲染方式
描述:
这种渲染方式有两种,一种是类方式渲染,一种是函数方式渲染。
语法:
<Route path="/home" component={Home} /> 或 <Route path="/home" component={(router)=><Home {…router} />} />
使用:
import React, { Component } from 'react' import { Route } from 'react-router-dom' // 匹配成功后渲染的组件 import RenderCmp from './views/Render' class App extends Component { render() { return ( <div> {/* component 类方式: 1.对于规则匹配成的组件没有办法去写逻辑,会直接渲染 2.规则匹配成功后,会给组件中的props自动映射对应的路由对象 3.当前载体中的state更新,它不会重新创建 */} <Route path="/" component={RenderCmp} /> {/* component 函数方式: 1.可以在规则匹配成功后,进行业务逻辑的判断来决定最终是否渲染 2.规则匹配成功后,它需要你把回调函数中的路由对象,手动的通过props传给要渲染的组件 3.当前的载体中的state如果,发生改变,则它对应匹配要渲染的组件会销毁并重新创建 建议: component属性的回调函数的方式,不要在工作中使用,可以用 render来代替 */} {/* <Route path="/" component={route => { if (true) { return <RenderCmp {...route} /> } return <div>没有权限</div> }} /> */} </div> ) } } export default App
1.2 render方式渲染
语法:
<Route path="/home" render={<!--{cke_protected}{C}%3C!%2D%2D%20%2D%2D%3E-->router=><Home {<!--{cke_protected}{C}%3C!%2D%2D%20%2D%2D%3E-->…router} />} />
使用:
import React, { Component } from 'react' import { Route } from 'react-router-dom' // 匹配成功后渲染的组件 import RenderCmp from './views/Render' class App extends Component { render() { return ( <div> {/* render渲染方式 它有component类的优点也有component回调的优点,但没有component回调中的缺点 */} <Route path="/" render={route => { if (true) { return <RenderCmp {...route} /> } return <div>没有权限</div> }} /> </div> ) } } export default App
1.3 案例-登录成功才能访问某个页面
定义路由规则:
import React, { Component } from 'react' import { Redirect, Route, Switch } from 'react-router-dom' // 匹配成功后渲染的组件 import RenderCmp from './views/Render' import Login from './views/Login' class App extends Component { render() { return ( <div> <Switch> <Route path="/login" component={Login} /> <Route path="/render" render={route => { if (sessionStorage.getItem('uid')) { return <RenderCmp {...route} /> } return <Redirect to="/login" /> }} /> </Switch> </div> ) } } export default App
登录页面:
import React, { Component } from 'react' class Login extends Component { render() { return ( <div> <h3>用户登录</h3> <button onClick={() => { sessionStorage.setItem('uid', 1) this.props.history.push('/render') }} > 登录一下 </button> </div> ) } } export default Login
1.4 children方式渲染
描述:
在组件渲染显示时,不是关注与它是否显示,而是在显示的时候关注于它的路由相关信息,才用到它。
语法:
// 全匹配 <Route path="/about" children={router =>{ return <div>children渲染</div> }} /> 或 // 精确匹配 <Route path="/about" children={<About />} />
使用:
import React, { Component } from 'react' import { Redirect, Route, Switch } from 'react-router-dom' // 匹配成功后渲染的组件 import RenderCmp from './views/Render' // import Login from './views/Login' class App extends Component { render() { return ( <div> {/* children属性中传入jsx元素,则它会根据path路径来匹配规则,如果匹配成功则渲染,不会自动注入路由对象到props中 */} {/* <Route path="/sdfsf" children={<RenderCmp />} /> */} {/* children属性为一个函数,则它的渲染不会根据路由规则来匹配渲染,它默认都会渲染出来 在此函数的形参中有一个路由对象,此对象中有一个match属性,如果当前访问的地址和path路径一致,则返回为对象,否则为null 函数方式: 如果你当前的页面中有一些显示的元素它在任何的地址中都要显示,且还要根据是否是激活路由,而高亮出来,就可以用它 */} <Route path="/home" children={route => { // console.log('match', route.match) // return <RenderCmp {...route} /> // 手动添加规则:路径一致才渲染 return route.match ? <RenderCmp {...route} /> : null }} /> </div> ) } } export default App
2. withRouter高阶组件
描述:
作用:把不是通过路由直接渲染出来的组件,将react-router 的 history、location、match 三个对象传入props对象上
默认情况下必须是经过路由匹配渲染的组件才存在this.props,才拥有路由参数,才能使用编程式导航的写法,执行this.props.history.push(‘/uri’)跳转到对应路由的页面,然而不是所有组件都直接与路由相连的,当这些组件需要路由参数时,使用withRouter就可以给此组件传入路由参数,此时就可以使用this.props
语法:
// 引入withRouter import { withRouter} from 'react-router-dom' // 执行一下withRouter export default withRouter(Cmp)
使用:
利用 withRouter 监听路由规则变化:
import React, { Component } from 'react' // withRouter 让非路由直接匹配渲染的组件中能得在this.props中得到路由对象 import { Redirect, Route, Switch, withRouter } from 'react-router-dom' // 匹配成功后渲染的组件 // import RenderCmp from './views/Render' import Home from './views/Home' import Detail from './views/Detail' // 装饰器写法 // @withRouter class App extends Component { state = { num: 100 } componentDidMount() { // 手动让第1次执行 this.listenerRouter(this.props.location) // 监听路由变化则触发 第1次它只注册,不执行回调 this.props.history.listen(this.listenerRouter) } listenerRouter = ({ pathname }) => { console.log('listener', pathname) // 只有登录直接访问,别的都要判断是否登录 if(pathname!=='/login'){ // 判断是否登录 // if(xxx) // this.props.history.replace('/login') return; } } render() { // console.log('app', this.props) return ( <div> <Switch> <Route path="/home" component={Home} /> <Route path="/detail" component={Detail} /> </Switch> </div> ) } } // 对应装饰器写法 // export default App export default withRouter(App)
3. 自定义导航组件
App.jsx:
import React, { Component } from 'react' import Mylink from './components/Mylink' import { Route, Switch } from 'react-router-dom' import Home from './views/Home' import About from './views/About' class App extends Component { render() { return ( <div className="app"> <Mylink tag="h3" to="/home"> home页面 </Mylink> <Mylink tag="h3" to="/about"> about页面 </Mylink> <hr /> {/* 路由规则 */} <Switch> <Route path="/home" component={Home} /> <Route path="/about" component={About} /> </Switch> </div> ) } } export default App
自定义导航组件:
// Fragment 它可以当作顶层元素来包裹子元素,但它不会编译成html元素 // Fragment 有简写,简写时,可以不需要导入Fragment组件 <></> // import React, { Component, Fragment } from 'react' import React, { Component } from 'react' import { withRouter, Route } from 'react-router-dom' import types from 'prop-types' @withRouter class Mylink extends Component { jumpUrl = () => { this.props.history.push(this.props.to) } render() { let { tag: Tag, children, to, activeClassName } = this.props return ( <> <Route path={to} children={({ match }) => { // 高亮 let className = match ? activeClassName : '' return ( <Tag className={className} onClick={this.jumpUrl}> {children} </Tag> ) }} /> </> ) } } // 字段限制 Mylink.propTypes = { to: types.string.isRequired, tag: types.string, activeClassName: types.string } // 默认值 Mylink.defaultProps = { tag: 'a', activeClassName: 'active' } export default Mylink
加载全部内容