美文网首页
react-router 入门笔记

react-router 入门笔记

作者: copyLeft | 来源:发表于2019-07-29 22:09 被阅读0次

    React-router 笔记 官方文档

    基本思路

    • react-router 通过react 组件的方式实现,
    • 路由相关的数据,通过props传递给组件调用,
    • 路由层级关系, 通过标签嵌套实现

    基础标签

    • BrowserRouter : 路由容器
      • 该组件只能包含单个元素
    • Route : 组件渲染出口
      • 必须包含在 BrowserRouter 中
      • exact 精确匹配
    • Link : 跳转链接
      • 必须包含在 BrowserRouter 中

    基本使用

    // react-router-demo
    import React, { Component } from 'react'
    import {
        BrowserRouter as  Router,
        Route,
        Link
    } from 'react-router-dom'
    
    // component
    import Btn from'./btn'
    
    // pages
    
    function home(props){
    
        return (
            <div className="home">
                home
            </div>
        )
    
    }
    
    function products(props){
        return (
            <div className="products">
                products
            </div>
        )
    }
    
    function about(props){
        return(
            <div className="about">
                about
            </div>
        )
    }
    
    function product(props){
       return (
    
        <div>
            product
        </div>
    
       )
    }
    
    // router-config
    
    const routerConfig = [
    
        {
            label: 'home',
            path:'/',
            component: home,
            exact: true,
    
        },
        {
            label: 'products',
            path: '/products',
            component: products,
            exact: true,
        },
        {
            label: 'about',
            path: '/about',
            component: about
        },
        { 
            label: 'procut',
            path: '/products/:id',
            component: product
        }
    
    ]
    
    // container
    
    export default class pages extends Component{
    
        render(){
    
            const buildLabel = () =>{
    
                let tempalte = [];
    
                for(let item of routerConfig){
                    tempalte.push(
    
                        <Btn key={item.label}>
                            <Link to={item.path}>
                                {item.label}
                            </Link>
                        </Btn>
                    )
                }
                return tempalte
            }
    
            return (
                <Router>
                    <div className='pages-container'>
    
                        <div className="tab">
                        {buildLabel()}
                        </div>
    
                        {
                            routerConfig.map((item) =>{
                                return (
                                    <Route exact={item.exact} key={item.label} path={item.path} component={item.component}/>
                                )
                            })
                        }
    
                    </div>
    
                </Router>
            )
    
        }
    
    }
    
    

    路由传参

    • 配置参数路径: path = '/:params'
    • 函数组件, 通过组件参数中的 match.params[paramName] 获取路由参数
    
    // pages
    function home(props){
    
        return (
            <div className="home">
                in home page
                <br/>
                router parmas: 
                <br/>
                { props.match.params.userId }
            </div>
        )
    
    }
    
    render(){
    
        return (
            <Router>
                <div className='pages-container'>
    
                    <Link to='/userId'>
                        to user page
                    </Link>
    
                    <Route exact path='/' component={home}></Route>
                    <Route path='/:userId' component={home}></Route>
    
                </div>
            </Router>
        )
    
    }
    
    

    重定向 Redirect

    通过返回组件 Redirect 实现重定向

     function subPage(props){
    
        return (
            <Redirect to={{
                pathname: '/in_show_page'
            }}></Redirect>
        )
    
     }
    
    return (
        <Router>
            <div className='pages-container'>
    
                <Link to='/subPage'>
                    to sub page
                </Link>
    
                {/* 参数路由 */}
                <Route path='/:userId' component={home}></Route>
    
                {/* 重定向路由 */}
                <Route path='/subPage' component={subPage}></Route>
    
            </div>
        </Router>
    )
    
    

    命令式导航(history)

    • 命令式导航,通过history上的方法实现
    • 为props 添加 history 参数, 在组件内部获取路由相关的参数,及控制路由动作

    withRouter

    • 对于 Route 绑定的组件,组要是页面,本身已经将 路由接口包裹在props中, 而其他组件想获取路由接口需要通过 withRouter(compoent) 处理.
    • withRouter 处理的组件必须包裹在 <Router> 标签中s, 也就是说, 子组件中路由参数等,来自于包裹的 Router 对象
    // 使用 withRouter 处理组件,组件props中将包含 路由相关对象, { match, location, history }
    
    // 定义组件
    function jump (props){
    
        const { match, location, history } = props;
        console.log(props)
    
        return (
    
            <div>
    
                <button onClick={ history.goBack }> back </button>
                <button onClick={ () =>{history.push('/home')} }> jump to home </button>
                <button onClick={ () =>{ history.replace('/subPage') } }> replace path </button>
    
            </div>
    
        )
    
    }
    
    // 在父组件中构件
    
      render(){
    
        return (
            <Router>
            <div className="route-render">
    
                <Link to='/history'> history </Link>
    
                <Route path='/history' component={withRouter(jump)} ></Route>
    
            </div>
            </Router>
        )
    
    }
    
    

    跳转拦截 (Prompt)

    • 使用Prompt, 可在路由跳转前,执行相关操作
    
    //跳转提示, 每次路由跳转,提示信息 
    <Prompt message="路由将跳转"/>
    
    //message 为函数
    <prompt message={ lcoation => (`跳转地址 ${location.pathname}`) } />
    
    // 带触发条件 when = Boolean
    <Propmt when={ location.pathname === '/home' } message='你将进入home页面' />
    
    // 
    
    

    标签API

    <Router>

    • history: 绑定history对象, 方便外部调用

    <Route>

    • component: 渲染组件, 组件props将包含, { match, location, history } 路由参数
    • render: 通过函数渲染组件, 通过渲染简单组件的方式, 及通过该方式,为子组件配置参数
    • children: 构建自定义链接标签,
    • path: 路由匹配地址
    • exac: 是否精确匹配
    • stric: 使用严格模式

    <Switch>

    • 多路径匹配时,只渲染就近配置路径下的组件
    
         /**
         * 路径为 '/' 只会渲染 home 组件
         */
    
        <Switch>
    
            <Route path='/' componet={home}/>
            <Route path='/about' componet={about}/>
            <Route path='/product' componet={product}/>
    
        </Switch>
    
    

    路由参数

    • match

      • params :查询参数
      • isExac : 是否精确匹配
      • path : 包含 basename 路径
      • url: Link 地址
    • location

      • key: 'ac3df4', // 标识符
      • pathname: '/somewhere' //路由地址
      • search: '?some=search-string',
      • hash: '#howdy',
      • state: { [userDefined]: true }
    • history

      • length : 记录条数
      • action : 当前记录
      • location : location
      • push: 添加纪录,(跳转页面)
      • replace: 替换当前记录 (跳转页面)
      • go: 跳转到某条记录
      • goBack: 回退
      • goForward: 前进

    路由嵌套

    • 我们知道路由组件都包含在 <BrowserRouter> 中, 且该标签只能包含单一子元素,我们可以认为该标签创建一个路由环境, 包含在该标签内的 路由组件无论层级数,都归属于该路由环境.
    
     //父组件
     <App>
        <BrowserRouter>
            <div>
                <Route path='/' component={Home} />           
                 <Route path='/about' component={About} /> 
    
                <Sub/>
            </div>
        </BrowserRouter>
     </App>
    
     //子组件
    
    <div className='sub'>
        <Link to='/about'> to about </Link>
    
        <Route path='/about'  rennder={ () =>( <div> in sub about </div> ) } />
    </div>
    
    /**
     * Sub中的路由组件 与App中的路由组件处于同一层级, 当点击 Link标签时, 将进入 About 而不是Sub的自定义组件
     */
    
    
    • 创建属于当前页的子路由需要,需要创建新的 '<BrowserRouter>' 标签, 在没有配置basename的情况下,子路由的路径将以上级路由路径为基础, 且优先匹配当前路由环境下的组件, 例如: 父组件路径: '/home' 子组件下有 <Route path='/sub'>, 实际路径为: '/home/sub' 所以在划分路径时, 需要注意路径嵌套的问题,如对根路径 '/' 的处理, 很可能出现,路由配置冲突。
    
    //父路由
    
    let AppRouter = [
    
      {
        label: 'home',
        path: '/',
        component: Home,
        exact: true
      },
      {
        label: 'user-center',
        path: 'user-center',
        component: UserCenter
      },
      {
        label: 'books',
        path: '/books',
        component: Books
      },
      {
        label: 'book',
        path: '/books:id',
        component: Books
      }
    
    ]
    
    return (
          <Router>
            <div className="App">
    
                <Switch>
                    {routes}
                </Switch>
    
            </div>
          </Router>
        );
    
    //子路由
    
      <Router>
       <div>
            <h4>路由</h4>
            <Link to='/books'>  to sub </Link>
    
            <Route path='/' render={ () =>( <div> 路由嵌套 path='/' </div> ) }></Route>
            <Route path='/books' render={ () =>( <div> 路由嵌套 path='/sub' </div> ) }></Route>
       </div>
    </Router>
    
     /*
     ** 这是个路由冲突的例子, 可以看到,在父组件和子组件中,都配置了路径 '/books', 
     ** 当触发 Link 跳转时,将显示自组件内的组件, 即显示: '路由嵌套,path=/sub'
     ** 看起来一切正常,但当我们刷新页面, 将进入主路由的 Books 组件, 所以对于这样的路由冲突,编写时不易发现
     */
    
    

    component, rander, children 的区别

    • component 是应用最多的渲染接口,一般组件使用该接口就可以了, 该接口在渲染是将调用creatElement 构建组件
    • rander 接受一个渲染函数, 构建时直接调用函数返回的模板, 不会调用creatElement, 这里是与component不同的地方, rander主要用在需要为组件传递一些 props参数时使用, 如果我们在component 中传入匿名函数包裹的组件, 该组件将被反复调用, 应该creatELement函数无法对匿名函数做比较。参考: React router的Route中component和render属性的使用
    • children 无论路径是否匹配都将被渲染, 不同的是, 对于已匹配的路径,children 组件内将获取到 match 参数

    自定义history

    • 一般在浏览器使用的路由为 BrowserRouter,该路由是封装后的Router,提供了默认的history,所以该路由没有history 接口, 我们可以使用Router 自定特定类型的Router
    
    import { Router} from 'react-router-dom'
    import { createBrowserHistory } from 'history'
    
    // 创建history
    const history = createBrowserHistory()
    
    // 包装原方法, 添加日志功能
    const go = history.go
    history.go = n => {
        console.log(`go to --> ${n}`)
        go(n)
    }
    
    // 监听路由变化, 重定向
    history.listen(( location, action ) => {
    
        const isLogin = false
        if( isLogin ) {
            setTimeout(() => {
                history.push("/login")
            })
        }
    
    })
    
    

    相关文章

      网友评论

          本文标题:react-router 入门笔记

          本文链接:https://www.haomeiwen.com/subject/ipfwrctx.html