美文网首页JavaScript 进阶营
React.js学习笔记(6) router-4全接触 + (

React.js学习笔记(6) router-4全接触 + (

作者: woow_wu7 | 来源:发表于2017-11-05 16:49 被阅读291次

    (一) react-router-dom 安装

    React Router被拆分成下面几个包:

    • react-router :React Router 核心
    • react-router-dom 用于 DOM 绑定的 React Router - (用于Web浏览器)
    • react-router-redux React Router 和 Redux 的集成 - (搭配redux)
    • react-router-native 用于 React Native 的 React Router -(用于ReactNative)
    • react-router-config 静态路由配置的小助手
     npm install react-router-dom --save
    

    (二) 组件

    (1) <BrowserRouter>

    (1) <BrowserRouter> 简介:

    对于网页项目,存在<BrowserRouter>与<HashRouter>两种组件:
    <BrowserRouter>组件:在服务区来管理动态请求时使用。
    <HashRouter>组件:用于静态网站。

    通常,我们更倾向选择 <BrowserRouter>

    • BrowserRouter: 浏览器自带的API,restful风格(需要后台做相应的调整);
    • HashRouter: 使用hash方式进行路由;
    • MemoryRouter: 在内存中管理history,地址栏不会变化。在reactNative中使用。
    (2) <BrowserRouter> 属性:
    • basename: string
      作用:为所有位置添加一个基准URL
      使用场景:假如你需要把页面部署到服务器的二级目录,你可以使用 basename 设置到此目录。
    
    <BrowserRouter basename="/calendar"/>                    // basename:string
    
    <Link to="/today"/> 最终渲染为 renders <a href="/calendar/today">
    
    
    • keyLength: number
      作用:设置它里面路由的 location.key 的长度。默认是6。(key的作用:点击同一个链接时,每次该路由下的 location.key都会改变,可以通过 key 的变化来刷新页面。)
      使用场景:按需设置。
    
     <BrowserRouter keyLength={12}/>
    
    

    (2) <Route>

    (1) <Route> 组件简介:

    <Route> 自带三个 render method 和三个 props 。

    • render methods 分别是:
      <Route component>
      <Route render>
      <Route children>
      每种 render method 都有不同的应用场景
      同一个<Route> 只使用一种 render method ,大部分情况下你将使用 component 。
      children方式渲染会不管地址栏是否匹配都渲染一些内容,在这里加动画一时很常见的做法。

    • props 分别是:
      match
      location
      history

    ( match, location, history 使用方法已在文章末尾补充 -2017/11/8 )

    三种渲染方式都会得到三个属性match、history、location;
    所有的 render method 无一例外都将被传入这些 props;
    渲染组件时,route props跟着一起渲染;

    
    <Route path="/user/:username" component={User}/>
    
    const User = ({ match }) => {
      return <h1>Hello {match.params.username}!</h1>
    }
    
    
    • exact: bool
      如果为 true,path 为 '/one' 的路由将不能匹配 '/one/two',反之,亦然。
    • strict: bool
      对路径末尾斜杠的匹配。如果为 true。path 为 '/one/' 将不能匹配 '/one' 但可以匹配 '/one/two'。
    • 如果要确保路由没有末尾斜杠,那么 strict 和
      exact 都必须同时为 true
     <Route exact strict path="/one" component={About}/>
    

    (3) <Link>

    • to: 后面可以接字符串,也可以跟对象(对象可以是动态地添加搜索的信息);

    to: string
    作用:跳转到指定路径
    使用场景:如果只是单纯的跳转就直接用字符串形式的路径。

    to: object
    作用:携带参数跳转到指定路径
    作用场景:比如你点击的这个链接将要跳转的页面需要展示此链接对应的内容,又比如这是个支付跳转,需要把商品的价格等信息传递过去。

    
    <Link to={{
      pathname: '/courses',
      search: '?sort=name',
      hash: '#the-hash',
      state: { fromDashboard: true }
    }}/>
    
    
    • replace: bool

    replace: 当设置为true时,点击链接后将使用新地址替换掉访问历史记录里面的原地址。

    为 true 时,点击链接后将使用新地址替换掉上一次访问的地址,什么意思呢,比如:你依次访问 '/one' '/two' '/three' ’/four' 这四个地址,如果回退,将依次回退至 '/three' '/two' '/one' ,这符合我们的预期,假如我们把链接 '/three' 中的 replace 设为 true 时。依次点击 one two three four 然后再回退会发生什么呢?会依次退至 '/three' '/one'!

    (4) <NavLink>

    <NavLink>是<Link>的一个特定版本, 会在匹配上当前URL的时候会给已经渲染的元素添加样式参数;

    • activeClassName: string
      导航选中激活时候应用的样式名,默认样式名为 active
    • activeStyle: object
      如果不想使用样式名就直接写style
    • isActive,添加额外逻辑判断是否生效 (决定导航是否激活,或者在导航激活时候做点别的事情。不管怎样,它不能决定对应页面是否可以渲染。)
    
    <NavLink
      to="/faq"
      activeClassName="selected"
    >FAQs</NavLink>
    
    

    (5) <Switch>

    • <Switch>会遍历自身的子元素(即路由)并对第一个匹配当前路径的元素进行渲染。
      ( 只渲染出第一个与当前访问地址匹配的 <Route> 或 <Redirect> )
    • <Switch> 对于转场动画也非常适用,因为被渲染的路由和前一个被渲染的路由处于同一个节点位置!
    
    <Fade>
      <Switch>
        {/* 用了Switch 这里每次只匹配一个路由,所有只有一个节点。 */}
        <Route/>
        <Route/>
      </Switch>
    </Fade>
    
    
    
    <Fade>
      <Route/>
      <Route/>
      {/* 不用 Switch 这里可能就会匹配多个路由了,即便匹配不到,也会返回一个null,使动画计算增加了一些麻烦。 */}
    </Fade>
    
    

    (6) <Redirect>

    • <Redirect/>可以写在<Route/>的render属性里面,也可以跟<Route/>平级;
    • to: string
      重定向的 URL 字符串
    • to: object
      重定向的 location 对象
    • push: bool
      若为真,重定向操作将会把新地址加入到访问历史记录里面,并且无法回退到前面的页面。
    • from: string
      需要匹配的将要被重定向路径。
    
    <Switch>
      <Route exact path="/" component={Home}/>
    
      <Route path="/users" component={Users}/>
      <Redirect from="/accounts" to="/users"/>                     // 将/accounts重定向到/users
    
      <Route component={NoMatch}/>
    </Switch>
    
    
    
    ------------------------------------------------------------------
    
    2018-1-23更
    
    import React, { Component } from 'react';
    import {Route, Redirect} from 'react-router-dom';                 // 引入Redirect
    import A from '../component/a.js';
    import B from '../component/b.js';
    
    class RouterOne extends Component {
      render() {
        return (
          <div className="R">
            <Route  path="/a" component={ A }/>
            <Route  path="/b" render={() => <Redirect to="/a"/>}/>    // 使用Redirect
          </div>
        );
      }
    }
    
    export default RouterOne;
    

    (7) <Prompt> 提示

    当用户离开当前页面前做出一些提示。用在Link或者Route的地方都行

    • message: string
      当用户离开当前页面时,设置的提示信息。
    • message: func
      当用户离开当前页面时,设置的回掉函数,函数是有默认参数的。
    • when: bool
      通过设置一定条件要决定是否启用 Prompt,属性值为true时启用防止转换;
    
    <Prompt message="确定要离开?" />
    
    





    (8) React-router4 使用

    
      import {
        BrowserRouter as Router, // 或者是HashRouter、MemoryRouter
        Route,   // 这是基本的路由块
        Link,    // 这是a标签
        Switch   // 这是监听空路由的
        Redirect // 这是重定向
        Prompt   // 防止转换  
      } from 'react-router-dom'
    
    

    实例:

    index.js入口文件
    
    
    import React from 'react';
    import ReactDOM from 'react-dom';
    import RouterComp from './router/router.js';
    
    import {
      BrowserRouter
    } from 'react-router-dom';
    
    import CommentApp from './commentApp'; 
    
    import './index.css'
    
    ReactDOM.render(
      (
        <BrowserRouter>
          <CommentApp>                                 
            <RouterComp />                                // RouterComp 存放所有Route
          </CommentApp>    
        </BrowserRouter>
      ),document.getElementById('root'))
    
    
    
    
    ------------------------------------------------------------------------------------------
    router.js
    
    
    
    import React, {Component} from 'react';
    import {
        Route, Redirect, Switch, Prompt
    } from 'react-router-dom';
    import CommentApp from '../commentApp';
    import ArrayC from '../component/ArrayC/ArrayC';
    import ObjectC from '../component/ObjectC/ObjectC';
    import RedirectComponents from '../component/Redirect/redirect';
    
    export default class RouterA extends Component {
        render() {
            return(
                <div>
                    <Switch>                                              // 匹配第一个匹配到的Route
                        <Route path="/array" component={ArrayC}/>
    
                        <Route path="/object" component={ObjectC}/>
                        <Redirect  from="/redirectgo" to="/object"/>               // 路由重定向
    
                        <Route path="/redirectgo" component={RedirectComponents}/>
                    </Switch>
                    <Prompt message="确定要离开?" />                               // 跳转前提示
                </div>
            )
        }
    }
    
    
    
    
    ------------------------------------------------------------------------------------------
    
    commentApp.js
    
    
    
    import React, {Component} from 'react'
    import {Link, NavLink} from 'react-router-dom'
    
    
    class CommentApp extends Component {
    
        render() {
            return (
                <div className='wrapper'>
    
                    <NavLink to="/array" activeClassName="abc" className='context2'>
                        <div>
                            数组测试
                        </div>
                    </NavLink>
                    <Link to="/object">
                        <div className='context3'>
                            对象测试
                        </div>
                    </Link>
                    <Link to="/redirectgo">
                        <div className='context4'>
                            重定向测试
                        </div>
                    </Link>
    
                    <div className="ArrayC">
                        {this.props.children}           // <RouterComp /> 组件加载的位置               
                    </div>
    
                 </div>
            )
        }
    }
    
    export default CommentApp
    
    






    (九) location

    location 是指你当前的位置,将要去的位置,或是之前所在的位置

    它看起来像这样:
    
    {
      key: 'ac3df4', // not with HashHistory!
      pathname: '/somewhere'
      search: '?some=search-string',
      hash: '#howdy',
      state: {
        [userDefined]: true
      }
    }
    
    

    (1)路由器将在几个地方为您提供一个 location 对象:

    • 在 Route component 中,以 this.props.location 获取
    • 在 Route render 中,以 ({location}) => () 方式获取
    • 在 Route children 中,以 ({location}) => () 方式获取
    • 在 withRouter 中,以 this.props.location 的方式获取

    (2) location 对象不会发生改变,因此可以在生命周期的回调函数中使用 location 对象来查看当前页面的访问地址是否发生改变。这种技巧在获取远程数据以及使用动画时非常有用

    
    
    componentWillReceiveProps(nextProps) {
      if (nextProps.location !== this.props.location) {
        // navigated!
      }
    }
    
    

    (3) 您可以使用location代替字符串导航到各个位置:

    • <Link to={location} />
    • <NaviveLink to={location} />
    • <Redirect to={location />
    • history.push(location)
    • history.replace(location)
    location
    它看起来像这样:
    
    
    {
      key: 'ac3df4', // not with HashHistory!
      pathname: '/somewhere'
      search: '?some=search-string',
      hash: '#howdy',
      state: {
        [userDefined]: true
      }
    }
    
    

    (十) match

    (1)match 对象包含了 <Route path> 如何与 URL 匹配的信息,具有以下属性:

    • params : object 路径参数,通过解析 URL 中的动态部分获得键值对
    • isExact : bool 为 true 时,整个 URL 都需要匹配
    • path : string 用来匹配的路径模式,用于创建嵌套的 <Route>
    • url : string URL 匹配的部分,用于嵌套的 <Link>

    (2) 在以下情境中可以获取 match 对象 ( 和location获取方法一样 )

    • 在 Route component 中,以 this.props.match获取
    • 在 Route render 中,以 ({match}) => () 方式获取
    • 在 Route children 中,以 ({match}) => () 方式获取
    • 在 withRouter 中,以 this.props.match的方式获取
    • matchPath 的返回值

    当一个 Route 没有 path 时,它会匹配一切路径。

    (十一) history

    在组件中使用this.props.history
    包含了以下信息:

    • length 保存的路由记录条数
    • action:push,pop,replace
    • location :当前路由信息
    • goBack
    • goForward等
    history包含内容









    2017/11/12日更新

    (十二) react-router4 实现按需加载

    • (1) 首先使用官方提供的 bundle 组件 (这个组件和你用webpack打包的bundle没啥关系)
      Bundle.js的主要功能就是接收一个组件异步加载的方法,并返回相应的react组件

    • 这里要注意:
      由于webpack2以上已经不支持import loader 了,所以下面的方法不用 bundle-loader插件

    bundle.js
    
    
    
    由于import是promise结构,所有在下面的load = XXXXXX部分也要用promise结构
    
    
    import React, {Component} from 'react'
    
    export default class Bundle extends Component {
    
      constructor(props) {
            super(props);
            this.state = {
                mod: null
            };
        }
    
        componentWillMount() {
            this.load(this.props)
        }
        componentWillReceiveProps(nextProps) {
            if (nextProps.load !== this.props.load) {
                this.load(nextProps)
            }
        }
    
    
    
    /*
        load = (props) => {
            this.setState({
                mod:null
            })
            props.load((mod) => {
                this.setState({
                    mod:mod.default?mod.default:mod
                })
            })
        }
    */
    
    上面注释这段需要修改为:
    load(props) {
            this.setState({
                mod: null
            });
            //注意这里,使用Promise对象; mod.default导出默认
            props.load().then((mod) => {
                this.setState({
                    mod: mod.default ? mod.default : mod
                });
            });
        }
    
    
    
    
     render() {
            return this.state.mod ? this.props.children(this.state.mod) : null;
        }
    
    
    }
    
    
    
    • (2)
      1.在router.js中引入官方提供的bundle.js组件
      2.在Route组件的component中使用bundle.js
      3.在<Bundle load={ () => import('........') }中采用import方法
    
    import React, {Component} from 'react';
    // import { Route, Redirect, Switch, Prompt } from 'react-router-dom';
    import { Route,  Switch } from 'react-router-dom';
    
    import Bundle from '../bundle/bundle.js';
    
    
    
    export default class RouterA extends Component {
        render() {
            return(
                <div>
                    <Switch>
    
                        <Route 
                        path="/array/go?name=123" 
                        component={ () => <Bundle load={() => import('../component/ArrayC/ArrayC')}>{ C => <C />}</Bundle>} 
                        />
    
                        <Route 
                        path="/object" 
                        component={ () => <Bundle load={ () => import('../component/ObjectC/ObjectC')}>{ C => <C /> }</Bundle>}
                        />
    
                        <Route
                         path="/redirectgo" 
                         component={ () => <Bundle load={ () => import('../component/Redirect/redirect')}>{ C => <C /> }</Bundle>} 
                         />
                         
                        <Route 
                        path="/string" 
                        component={ () => <Bundle load={ () => import('../component/string/strig.js')}>{ C => <C /> }</Bundle>}
                        />  
                                       
                    </Switch>
                </div>
            )
        }
    }
    
    
    按需加载效果图
    ( 填坑 ) http://www.jianshu.com/p/547aa7b92d8c
    ( 踩坑 ) http://www.jianshu.com/p/d712a5030c13

    相关文章

      网友评论

        本文标题:React.js学习笔记(6) router-4全接触 + (

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