利用react-router实现按需加载、登录验证、刷新组件。。。

 阅读约 16 分钟

由于React Router 4.0已经正式发布,所以该博文分React Router 和 React Router 4.0 进行分类讨论!该博文会持续更新中,欢迎大家一起讨论与补充!

我相信用过react一般都用过react-router,那就很有必要说说用react-router实现的一些常用功能了,比如组件按需加载、用户登录验证、刷新当前路由。。。在这篇文章中,我将列出一些react-router使用小技巧,希望每个读者都能至少从中学到一个有用的技巧!

一、按需加载

React Router:使用 getComponent + require.ensure 实现按需加载

getComponent 相比以前的 component 属性,这个方法是异步的,也就是当路由匹配时,才会调用这个方法。

require.ensure(dependencies, callback, chunkName)

require.ensure 是 webpack 提供的方法,这也是按需加载的核心方法。第一个参数是依赖的模块数组,第二个是回调函数,该函数调用时会传一个require参数,第三个是模块名,用于构建时生成文件时命名使用

实现按需加载核心代码如下:

import React, { Component } from 'react'; // react核心
import { Router, Route, Redirect, IndexRoute, browserHistory } from 'react-router'; 

/**
 * (路由根目录组件,显示当前符合条件的组件)
 * 
 * @class Roots
 * @extends {Component}
 */
class Roots extends Component {
    render() {
        return (
            <div>{this.props.children}</div>
        );
    }
}

const history = browserHistory;

// 首页
const home = (location, cb) => {
    require.ensure([], require => {
        cb(null, require('./Home').default);
    }, 'home');
}

const RouteConfig = (
    <Router history={history}>
        <Route path="/" component={Roots}>
            <IndexRoute getComponent={home} />   
            <Route path="/home" getComponent={home} /> 
            <Route path="/login" component={login} />
            <Redirect from="*" to="/home" />
        </Route>
    </Router>
);

export default RouteConfig;

React Router 4.0:使用 babel-plugin-syntax-dynamic-import + react-loadable 实现按需加载

首先确保已安装 babel-plugin-syntax-dynamic-import react-loadable,未安装请先安装:

npm i -D babel-plugin-syntax-dynamic-import

npm i -S react-loadable

实现按需加载核心代码如下:

import React, { Component } from 'react';
import { BrowserRouter, HashRouter, Switch, Route, Redirect} from 'react-router-dom';
import createBrowserHistory from 'history/createBrowserHistory'
const history = createBrowserHistory();

// 按路由拆分代码
import Loadable from 'react-loadable';

const loadingComponent = ({ isLoading, error }) => {
  // Handle the loading state
  if (isLoading) {
      return <div>Loading...</div>;
  }
  // Handle the error state
  else if (error) {
      return <div>Sorry, there was a problem loading the page.</div>;
  }
  else {
      return null;
  }
};

const Index = Loadable({
  loader: () => import('./Index'),
  loading: loadingComponent
});

const Home= Loadable({
  loader: () => import('./Home'),
  loading: loadingComponent
});

const Login= Loadable({
  loader: () => import('./Login'),
  loading: loadingComponent
});

/**
 * (路由根目录组件,显示当前符合条件的组件)
 * 
 * @class Roots
 * @extends {Component}
 */
class Roots extends Component {
    render() {
        return (
            <div>{this.props.children}</div>
        );
    }
}

let Router = process.env.NODE_ENV !== 'production' ? BrowserRouter : HashRouter;

const RouteConfig = (
    <Router history={history}>
        <Switch>
            <Route path="/" exact component={Index} />
            <Route path="/home" component={Home} />
            <Route path="/login" component={Login} />
            <Redirect from='' to="/" />
        </Switch>
    </Router>
);

export default RouteConfig;

二、实现登录验证

React Router:利用 Route 的 onEnter 钩子在渲染对象组件前做拦截操作实现登录验证;

import React, { Component } from 'react'; // react核心
import { Router, Route, Redirect, IndexRoute, browserHistory } from 'react-router'; 

/**
 * (路由根目录组件,显示当前符合条件的组件)
 * 
 * @class Roots
 * @extends {Component}
 */
class Roots extends Component {
    render() {
        return (
            <div>{this.props.children}</div>
        );
    }
}

const history = browserHistory;

// 首页
const home = (location, cb) => {
    require.ensure([], require => {
        cb(null, require('./Home').default);
    }, 'home');
}

// 登录验证
const requireAuth = (nextState, replace) => {
    if(true) { // 未登录
        replace({
            pathname: '/login',
            state: { nextPathname: nextState.location.pathname }
        });
    } 
}

const RouteConfig = (
    <Router history={history}>
        <Route path="/" component={Roots}>
            <IndexRoute getComponent={home} onEnter={requireAuth} />   
            <Route path="/home" getComponent={home} onEnter={requireAuth} /> 
            <Route path="/login" component={login} />
            <Redirect from="*" to="/home" />
        </Route>
    </Router>
);

export default RouteConfig;

React Router4.0:在 Route 的 render 属性上添加一个函数实现登录验证;

实现登录验证核心代码如下:

import React, { Component } from 'react';
import { BrowserRouter, HashRouter, Switch, Route, Redirect} from 'react-router-dom';
import createBrowserHistory from 'history/createBrowserHistory'
const history = createBrowserHistory();

// 按路由拆分代码
import Loadable from 'react-loadable';

const loadingComponent = ({ isLoading, error }) => {
  // Handle the loading state
  if (isLoading) {
      return <div>Loading...</div>;
  }
  // Handle the error state
  else if (error) {
      return <div>Sorry, there was a problem loading the page.</div>;
  }
  else {
      return null;
  }
};

const Index = Loadable({
  loader: () => import('./Index'),
  loading: loadingComponent
});

const Home= Loadable({
  loader: () => import('./Home'),
  loading: loadingComponent
});

const Login= Loadable({
  loader: () => import('./Login'),
  loading: loadingComponent
});

/**
 * (路由根目录组件,显示当前符合条件的组件)
 * 
 * @class Roots
 * @extends {Component}
 */
class Roots extends Component {
    render() {
        return (
            <div>{this.props.children}</div>
        );
    }
}

// 登录验证
function requireAuth(Layout, props) {
  if (true) { // 未登录
    return <Redirect to="/login" />;
  } else {
    return <Layout {...props} />
  }
}

let Router = process.env.NODE_ENV !== 'production' ? BrowserRouter : HashRouter;

const RouteConfig = (
    <Router history={history}>
        <Switch>
            <Route path="/" exact component={Index} />
            <Route path="/home" component={props => requireAuth(Home, props)} />
            <Route path="/login" component={Login} />
            <Redirect from='' to="/" />
        </Switch>
    </Router>
);

export default RouteConfig;

三、实现点击左侧菜单刷新当前组件

React Router:利用 Route 的 createElement 钩子实现点击左侧菜单刷新当前组件;

实现点击左侧菜单刷新当前组件核心代码如下:

import React, { Component } from 'react'; // react核心
import { Router, Route, Redirect, IndexRoute, browserHistory } from 'react-router'; 

/**
 * (路由根目录组件,显示当前符合条件的组件)
 * 
 * @class Roots
 * @extends {Component}
 */
class Roots extends Component {
    render() {
        return (
            <div>{this.props.children}</div>
        );
    }
}

const history = browserHistory;

// 首页
const home = (location, cb) => {
    require.ensure([], require => {
        cb(null, require('./Home').default);
    }, 'home');
}

// 此处为要点击刷新的组件
const arr = [
    home
];

// 开关优化
let onOff =false;

// 页面强制刷新,如果需要强制刷新在路由中添加onChange事件以及在组件数组添加
const createElement=(component, props) =>{
    if (props.children && onOff || props.children && arr.includes(props.routes.slice(-1)[0].getComponent)) {
        let children = Object.assign({}, props.children, {key : `${window.location.pathname}` + new Date().getTime()})
        props = { ...props, children };
        onOff = false;
    }
    return React.createElement(component, props)
 }

 const onChange = (props, next) => {
     onOff = true
     console.log(`${next.location.pathname}`, 'change');
 }

const RouteConfig = (
    <Router history={history} createElement = {createElement}>
        <Route path="/" component={Roots}>
            <IndexRoute getComponent={home} />   
            <Route path="/home" getComponent={home} /> 
            <Route path="/login" component={login} />
            <Redirect from="*" to="/home" />
        </Route>
    </Router>
);

export default RouteConfig;

React Router4.0:直接使用 history.replace 实现点击左侧菜单刷新当前组件即可;

欢迎大家一起讨论react-router使用小技巧,该博文会持续更新!

阅读 12.7k更新于 2018-04-13
推荐阅读
每天一探
用户专栏

保持专注并持续发布(stay focused and keep shipping)

52 人关注
9 篇文章
专栏主页
目录