React基于路由进行代码分割 您所在的位置:网站首页 react代码生成器 React基于路由进行代码分割

React基于路由进行代码分割

2022-12-27 10:44| 来源: 网络整理| 查看: 265

theme: fancy highlight: agate

你好,我是南一。这是我在准备面试八股文的笔记,如果有发现错误或者可完善的地方,还请指正,万分感谢🌹

这两天整理项目经历,看到这一个知识点,重新实现了一遍,顺便记录一下。

一、为什么要做代码分割和懒加载?

背景: 随着项目开发,业务功能增加,代码量随着增长,代码包体积日渐肥胖,尤其是整合了多种第三方库,导致代码包体积过大,加载时间长,性能下降。

对策: WebPack 等打包工具早有代码分离的特性来应对这种问题,将代码分离到不同的 bundle 中,需要时按需加载就可以极大改善加载时间长的问题。常见的代码分离方法有三种:

入口起点:使用 entry 配置手动地分离代码。 防止重复:使用 Entry dependencies 或者 SplitChunksPlugin 去重和分离 chunk。 动态导入:通过模块的内联函数调用来分离代码。

今天我们就是采用动态导入来实现分包。

决定在哪引入代码分割需要一些技巧。需要确保选择的位置能够均匀地分割代码包而不会影响用户体验。

一个不错的选择是从路由开始。大多数网络用户习惯于页面之间能有个加载切换过程。

实现将代码按照路由进行分割,只在访问该路由的时候才加载该页面内容,可以提高首屏加载速度。

二、知识预知 1、import()

import :ES6语法,使用export命令定义了模块的对外接口以后,其他 JS 文件就可以通过import命令加载这个模块。

import()ES6语法,可用于动态引入模块,返回一个 Promise 对象。

WebPack解析代码时,遇到import()会作为一个分割点,将导入的模块作为一个单独的bundle打包。如果是使用脚手架 Create React App 搭建的项目,可直接使用此功能。

import("./a").then(res => { console.log(res); });

这里我花了很多时间试错,经测试发现,import()语法如果是包含在函数或者循环内,webpack的代码分割会失效,所以后面我用了路由表配置的方式去实现,如果有更优雅的实现方式可以在评论区分享。

2、React.lazy

React.lazy 函数能让你像渲染常规组件一样处理动态引入(的组件)。React.lazy 接受一个函数,这个函数需要动态调用 import()。它必须返回一个 Promise,该 Promise 需要 resolve 一个 default export 的 React 组件。

const OtherComponent = React.lazy(() => import('./OtherComponent')); 3、Suspense

然后应在 Suspense 组件中渲染 lazy 组件,如此使得我们可以使用在等待加载 lazy 组件时做优雅降级(如 loading 指示器等)。

import React, { useState, lazy, Suspense } from 'react' import Loading from '@/component/Loading'; function App() { const [RouteRouter] = useState(() => { return lazy(() => import('@/routes/RouteRouterSplit')) }) return } 三、具体实现

路由表设计,我选择了最笨的方式实现

export const routerConfig = [ { path: '/', component: lazy(() => import('@/pages')) }, { path: '/Login', component: lazy(() => import('@/pages/Login')), }, { path: '/Home', component: lazy(() => import('@/pages/Home')) } { path: '/Render', component: lazy(() => import('@/pages/Render')) }, { path: '/Test', component: lazy(() => import('@/pages/Test')) } ]

为了更好用我还做了路由拦截和路由鉴权,

路由鉴权:采用 context 将路由权限向下传递,用 useContext 获取权限,并做筛选。

路由拦截: 用高阶组件对页面组件进行包裹,在页面加载前后调用处理函数

import React, { useState, useLayoutEffect, lazy, Suspense, useMemo } from 'react' import Loading from '@/component/Loading'; export const Permission = React.createContext() function App() { const [rootPermission, setRootPermission] = useState([]) const [RouteRouter] = useState(() => { return lazy(() => import('@/routes/RouteRouterSplit')) }) useLayoutEffect(() => { setRootPermission([ '/', '/NoPermission', '/WriteDoc', '/Home', '/Login', ]) }, []) const config = useMemo(() => ({ before: function () { // console.log('before'); }, after: function () { // console.log('after'); }, }), []) return } export default App import { lazy, useContext, useLayoutEffect } from 'react'; import { Route, Routes } from 'react-router-dom' import { Permission } from '@/App' import { routerConfig } from './routerConfig' const NoFound = lazy(() => import('@/component/NoFound')) /** * 鉴权函数,判断此组件是否在权限范围内 (不同的鉴权方式可在此函数中修改) * @param {Array} permissionList * @param {string} componentName */ function authentication(permissionList, componentName) { return permissionList.indexOf(componentName) >= 0 } /** * 路由拦截 * @param {*} Component * @param {*} config * @returns */ function RouteInterception(Component, config) { const { before, after } = config || {} return function ProRouteComponent(props) { // const ref = useRef() // 进入路由前触发 before && before() // 路由挂载之后触发 useLayoutEffect(() => { after && after() }, []) return } } export default function RouteRouter(props) { // 获取权限数组 const permissionList = useContext(Permission) const routes = routerConfig.filter(({ path }) => { // 权限筛选 return authentication(permissionList, path) }).map(({ path, component: Component }) => { // 路由拦截 Component = RouteInterception(Component, props.config) return }) return ( {routes} ) }

打包完就是这样效果

React基于路由进行代码分割 插图1

本文正在参加「金石计划 . 瓜分6万现金大奖」

温馨提示:本文最后更新于2022-12-12 00:49:59,某些文章具有时效性,若有错误或已失效,请在下方留言或联系烟雨网


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有