CcbeanBlog CcbeanBlog
首页
  • 前端文章

    • JavaScript
    • HTML+CSS
    • Vue
    • React
  • 系列笔记

    • React使用学习
    • Vue2源码探究
  • Node文章

    • 基础
    • 问题
    • 框架
  • 系列笔记

    • 数据结构与算法
  • 构建工具文章

    • webpack
  • 系列笔记

    • Webpack5使用学习
  • MySQL
  • Linux
  • 网络
  • 小技巧
  • 杂记
  • 系列笔记

    • Protobuf Buffers
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Ccbean

靡不有初,鲜克有终
首页
  • 前端文章

    • JavaScript
    • HTML+CSS
    • Vue
    • React
  • 系列笔记

    • React使用学习
    • Vue2源码探究
  • Node文章

    • 基础
    • 问题
    • 框架
  • 系列笔记

    • 数据结构与算法
  • 构建工具文章

    • webpack
  • 系列笔记

    • Webpack5使用学习
  • MySQL
  • Linux
  • 网络
  • 小技巧
  • 杂记
  • 系列笔记

    • Protobuf Buffers
关于
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • JavaScript

  • HTML+CSS

  • Vue

  • React

    • Redux原理学习
    • Apollo-Client简介
    • React零碎点总结
    • react实现按需加载-代码分割(上)
    • react实现按需加载-代码分割(下)
      • 构建自己的redux
    • TypeScript

    • 系列笔记

    • 前端
    • React
    ccbean
    2017-12-29
    目录

    react实现按需加载-代码分割(下)

    # react实现按需加载-代码分割(下)

    # 前言

    上节中所使用的webpack配置的时候所安装的react,可以使用bundle-loader来实现按需加载,但是在create-react-app中使用会出现报错:

    Line 4:   Unexpected '!' in 'bundle-loader?lazy&name=login!./container/login/login'. Do not use import syntax to configure webpack loaders                 import/no-webpack-loader-syntax
    Line 5:   Unexpected '!' in 'bundle-loader?lazy&name=register!./container/register/register'. Do not use import syntax to configure webpack loaders        import/no-webpack-loader-syntax
    

    这是因为create-react-app不支持webpack-loader,具体的可以看看这个issue (opens new window),在这个issue中给出了解决方案。

    # 一、根据router实现按需加载

    1.未按需加载前,原文件router.js

    import React from 'react';
    import {Route,Switch,Redirect} from 'react-router-dom';
    import Login from './container/login/login'
    import Register from "./container/register/register";
    import Bossinfo from "./container/bossinfo/bossinfo";
    import Geniusinfo from "./container/geniusinfo/geniusinfo";
    import AuthRoute from "./components/authroute/authroute";
    import Dashboard from "./components/dashboard/dashboard";
    import Chat from './components/chat/chat';
    
    class App extends React.Component{
        constructor(props){
            super(props);
            this.state = {
                hasError:false
            }
        }
    
        componentDidCatch(err,info){
                this.setState({
                hasError:true
            })
        }
    
        render(){
            return(
                this.state.hasError ? <Redirect to='/msg'></Redirect>
                    :
                <div>
                    <AuthRoute/>
                    <Switch>
                        <Route path='/login' component={Login}></Route>
                        <Route path='/register' component={Register}></Route>
                        <Route path='/bossinfo' component={Bossinfo}></Route>
                        <Route path='/geniusinfo' component={Geniusinfo}></Route>
                        <Route path='/chat/:user' component={Chat}></Route>
                        <Route component={Dashboard}></Route>
                    </Switch>
                </div>
            )
        }
    }
    

    2.使用AsyncComponent.js,最原始的:

    import React, { Component } from 'react'
    
    class Bundle extends Component {
      constructor() {
        super()
        this.state = {
          mod: null
        }
      }
    
      async componentDidMount() {
        const {default: mod} = await this.props.load()
    
        this.setState({
          mod: mod.default || mod
        })
      }
    
      render() {
        return (
          this.state.mod ? this.props.children(this.state.mod) : null
        )
      }
    }
    
    export default Bundle
    

    然后在入口文件中这么使用:

    import React from 'react'
    import {
      BrowserRouter,
      Route
    } from 'react-router-dom'
    import Bundle from './bundle'
    
    let CodeSplit = () => {
      return (
        <BrowserRouter>
          <div>
            <Route path={'/cp1'} render={() => {
              return (<Bundle load={() => import('./cp1')}>
                {(Cp1) => <Cp1></Cp1>}
              </Bundle>)
            }
            }></Route>
    
            <Route path={'/cp2'} render={() => {
              return (<Bundle load={() => import('./cp2')}>
                {(Cp2) => <Cp2></Cp2>}
              </Bundle>)
            }
            }></Route>
          </div>
        </BrowserRouter>
      )
    }
    
    
    export default CodeSplit
    

    这样进行使用太麻烦了,可以进行优化改进,下面是改进的使用方案,让其能够更优雅地进行使用。

    3.创建文件AsyncComponent.js,因为import返回一个promise,所以我们这里将componentDidMount变成一个async函数

    import React, { Component } from "react";
    
    export default function asyncComponent(importComponent) {
      class AsyncComponent extends Component {
        constructor(props) {
          super(props);
    
          this.state = {
            component: null
          };
        }
    
        async componentDidMount() {
          const { default: component } = await importComponent();
    
          this.setState({
            component: component
          });
        }
    
        render() {
          const C = this.state.component;
    
          return C ? <C {...this.props} /> : null;
        }
      }
    
      return AsyncComponent;
    }
    

    4.使用AsyncComponent

    我们原来导入组件:

    import Home from "./containers/Home";
    

    现在导入组件:

    const AsyncHome = asyncComponent(() => import("./containers/Home"));
    

    当创建AsyncHome时,调用的函数asyncComponent会动态地import组件;然后Route使用:

    <Route path="/" exact component={AsyncHome} />
    

    使用示例:

    import asyncComponent from './async-component'
    
    // 获取到异步组件
    const AsyncDemo = asyncComponent(() => import('./demo'))
    
    //...
    render() {
      return (
        <Route path="/demo" component={AsyncDemo}></Route>
      )
    }
    
    // 如果要传参 这样会router中的参数以0下标传入,感觉并不合理,还没找到合理的办法 更合理的办法应该是修改async函数,但是不知道怎么修改 不知道我这理解对不对
    render() {
      return (
        <Route path="/demo" render={(...props) => {
            <AsyncDemo test="hello" {...props}></AsyncDemo>
        }}></Route>
      )
    }
    

    然后修改入口文件就像这样:

    import React from 'react';
    import {Route,Switch,Redirect} from 'react-router-dom';
    import asyncComponent from './Bundle'
    const Login = asyncComponent(() => import("./container/login/login"));
    const Register = asyncComponent(() => import("./container/register/register"));
    const Bossinfo = asyncComponent(() => import("./container/bossinfo/bossinfo"));
    const Geniusinfo = asyncComponent(() => import("./container/geniusinfo/geniusinfo"));
    const AuthRoute = asyncComponent(() => import("./components/authroute/authroute"));
    const Dashboard = asyncComponent(() => import("./components/dashboard/dashboard"));
    const Chat = asyncComponent(() => import("./components/chat/chat"));
    
    
    class App extends React.Component{
        constructor(props){
            super(props);
            this.state = {
                hasError:false
            }
        }
    
        componentDidCatch(err,info){
            console.log(err,info);
            this.setState({
                hasError:true
            })
        }
    
        render(){
            return(
                this.state.hasError ? <Redirect to='/msg'></Redirect>
                    :
                <div>
                    <AuthRoute/>
                    <Switch>
                        <Route path='/login' component={Login}></Route>
                        <Route path='/register' component={Register}></Route>
                        <Route path='/bossinfo' component={Bossinfo}></Route>
                        <Route path='/geniusinfo' component={Geniusinfo}></Route>
                        <Route path='/chat/:user' component={Chat}></Route>
                        <Route component={Dashboard}></Route>
                    </Switch>
                </div>
            )
        }
    }
    
    export default App;
    

    执行npm run build可看到文件被code-spliting

    点击

    ###二、以组件为中心进行代码分片

    待续···

    编辑 (opens new window)
    上次更新: 2021/11/10, 12:11:50
    react实现按需加载-代码分割(上)
    构建自己的redux

    ← react实现按需加载-代码分割(上) 构建自己的redux→

    最近更新
    01
    阅读精通正则表达式总结
    09-29
    02
    项目搭建规范的配置
    07-15
    03
    Vite的使用
    07-03
    更多文章>
    Theme by Vdoing | Copyright © 2018-2023 Ccbeango
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式