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

41

由于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使用小技巧,该博文会持续更新!


如果觉得我的文章对你有用,请随意赞赏

你可能感兴趣的

朋也 · 2017年12月23日

博主,如果从列表(列表里面可能做了一些筛选和分页)然后点一项进到详情,然后再从详情返回到列表,这时候列表里的状态还能保持吗?也就是说假如之前列表翻页到第二页之后点击进入的详情,从详情返回到列表还是第二页的状态吗?

回复

0

这个要把页码当作路由的一部分了!

一探 作者 · 2017年12月23日
0

@sosout 就算当作路由了,那列表页面滚动的位置还是记不住,从详情页返回到列表页,页面位置会回到顶部

朋也 · 2017年12月23日
0

@朋也 react-rounte 不能实现状态的缓存,也就是你提到的信息,状态会丢失。您可以看看react-keeper:https://github.com/vifird/rea...

一探 作者 · 2017年12月24日
我也试着去用心 · 2018年04月04日

老哥 求一份直接能跑的demo

回复

0

@我也试着去用心 我github好多react示例,你可以看看

一探 作者 · 2018年04月04日
liukang · 2018年11月30日

老哥,求git地址

回复

黄小胖 · 2月20日

点击左侧菜单修改当前组件,为何不用Link和Route做,在顶层配置Link和Route的URL=>Component映射,然后点击Link就会自动更新。。不需要专门调replace API吧

回复

our_sky · 4月12日

登录认证重定向去登录,然后回来,之前的组件render函数没有重渲染。导致以为还是未认证接着跳到了登录认证页

回复

载入中...