本文同步公布在我的 Github 集体博客
前言
如果你的我的项目正在应用 react-toastify
,能够看看本文。我是最近通过webpack-bundle-analyzer
发现的一个问题,其实咱们只有某个页面会可能用到弹框,比方你点了珍藏之后会有弹框出来。然而通过打包后果和运行得出,每个页面无论有没有应用,一开始都引入了 react-toastify
。
react-toastify 的应用
如果你关上它 Github,它是这么应用的:
import React from 'react';import { ToastContainer, toast } from 'react-toastify';import 'react-toastify/dist/ReactToastify.css';function App(){ const notify = () => toast("Wow so easy!"); return ( <div> <button onClick={notify}>Notify!</button> <ToastContainer /> </div> );}
而如果整个我的项目多个中央用或者须要管制好数据流的话,一个做法往往是把它拉到 Redux 治理,在咱们我的项目就变成
app.tsx
// 外面封装了逻辑和返回了 <ToastContainer />import Toast from "src/containers/Toast";const { noToast } = this.propsreturn ( /* ... */ {!noToast && <Toast />})
我的项目应用的是 Next.js
咱们的每个pages/
页面都引入了这个app.tsx
公共文件,下面代码中,Toast是通过 Redux 等封装好的 Toast组件,由下面代码粗略看出,如果在每个页面的app.tsx
组件传入noToast
属性,那么<Toast />
就不会被加载,调用 toast
办法也不会有弹框呈现。
这段代码曾经是几年前的了,揣测是这个用意,默认导入,假如确认你页面真的不须要弹框,就传noToast
属性,然而我搜寻了整个我的项目,用到noToast
的中央只有一个,所以这个属性并不被起初接手的人所知,也就不会手动传入noToast
,导致每个页面都引入了react-toasify
应用toast办法必须页面要挂载了 <ToastContainer />
,才能够弹出弹框
现有的问题
- 咱们只有在页面详情页点击珍藏,才会有弹框(应用
react-toastify
),其余页面都没有。但每个页面都加载了该 chunk 包 - 我的项目中应用 toast 办法是通过Redux触发,通过
useUpdateEffect
监听了全局
src/containers/Toast.tsx
useUpdateEffect(() => { // toastProp从redux获取而来的 if (toastProp.message || toastProp.errors) notify(toastProp); // notify外面判断和调用toast}, [notify, toastProp]);
优化
- 当然是不要每个页面都引入,而是用到的页面再引入
- 最好用到的页面,没点击时也不加载,比方只有点击珍藏,才让
react-toasify
加载。
这就让人想到动静导入了,做法即是不再须要在app.tsx
判断引入react-toastify
,如新封装了一个组件
import { ToastContent, ToastOptions } from "react-toastify"; // 动静导入 ./Toastify是封装好的 Toastify export const toastify = () => import("./Toastify"); export const toast = (message: ToastContent, toastOptions?: ToastOptions) => { return toastify().then((toast) => { toast.showToast(message, toastOptions); }); };
下面做到的成果即是:
// beforeimport { toast } from "./toastify";toast("Hello World");// afterimport("./toastify").then(module => { module.toast("Hello World");});
当初看看这个文件 ./Toastify.tsx
(省略很多代码...)
const setupToastContainer = () => { if (!hasToastContainer) { hasToastContainer = true; // 须要去给根html增加一个div,id为 root-toastify ReactDOM.render( <> <ToastGlobalStyle /> <ToastWrapper/> </>, document.getElementById("root-toastify") ); } }; export const showToast = (message, toastOptions = {}) => { setupToastContainer(); toast(message, toastOptions);};
间接解脱了 Redux 依赖,而且只有你点击的一瞬间才会加载react-toastify
的chunk包,初始加载并不会,故最初优化后果是每个页面都打包压缩体积都缩小15-20K+。
这次就有点偷懒写文了,因为这只是我的项目优化的其中一个小点,以前也没有记录优化点,这次做了就马上回顾一下,下面代码可能看的有点懵,没有放出残缺代码和做个Demo。
不过没关系,因为我在 Github 找到了残缺的 PR 例子供大家参考 enhancement: move react-toastify to its own bundle,同样是动静导入react-toastify
,做法一样。
ps:
- 集体技术博文 Github 仓库