1. 值得收藏的UmiJS 教程

        共 12559字,需瀏覽 26分鐘

         ·

        2021-11-07 11:03

        點(diǎn)擊上方關(guān)注?前端技術(shù)江湖一起學(xué)習(xí),天天進(jìn)步



        前言

        網(wǎng)上的umi教程是真的少,很多人都只寫了一點(diǎn)點(diǎn),很多水文,所以打算自己寫一篇,自己搭建umi,并封裝了一下常用的功能,并用到公司實(shí)際項(xiàng)目中.

        umi介紹

        Umi 是什么?

        Umi,中文可發(fā)音為烏米,是可擴(kuò)展的企業(yè)級(jí)前端應(yīng)用框架。Umi 以路由為基礎(chǔ)的,同時(shí)支持配置式路由和約定式路由,保證路由的功能完備,并以此進(jìn)行功能擴(kuò)展。然后配以生命周期完善的插件體系,覆蓋從源碼到構(gòu)建產(chǎn)物的每個(gè)生命周期,支持各種功能擴(kuò)展和業(yè)務(wù)需求。

        Umi 是螞蟻金服的底層前端框架,已直接或間接地服務(wù)了 3000+ 應(yīng)用,包括 java、node、H5 無(wú)線、離線(Hybrid)應(yīng)用、純前端 assets 應(yīng)用、CMS 應(yīng)用等。他已經(jīng)很好地服務(wù)了我們的內(nèi)部用戶,同時(shí)希望他也能服務(wù)好外部用戶。

        它主要具備以下功能:

        • ???可擴(kuò)展,Umi 實(shí)現(xiàn)了完整的生命周期,并使其插件化,Umi 內(nèi)部功能也全由插件完成。此外還支持插件和插件集,以滿足功能和垂直域的分層需求。
        • ???開(kāi)箱即用,Umi 內(nèi)置了路由、構(gòu)建、部署、測(cè)試等,僅需一個(gè)依賴即可上手開(kāi)發(fā)。并且還提供針對(duì) React 的集成插件集,內(nèi)涵豐富的功能,可滿足日常 80% 的開(kāi)發(fā)需求。
        • ???企業(yè)級(jí),經(jīng)螞蟻內(nèi)部 3000+ 項(xiàng)目以及阿里、優(yōu)酷、網(wǎng)易、飛豬、口碑等公司項(xiàng)目的驗(yàn)證,值得信賴。
        • ???大量自研,包含微前端、組件打包、文檔工具、請(qǐng)求庫(kù)、hooks 庫(kù)、數(shù)據(jù)流等,滿足日常項(xiàng)目的周邊需求。
        • ???完備路由,同時(shí)支持配置式路由和約定式路由,同時(shí)保持功能的完備性,比如動(dòng)態(tài)路由、嵌套路由、權(quán)限路由等等。
        • ???面向未來(lái),在滿足需求的同時(shí),我們也不會(huì)停止對(duì)新技術(shù)的探索。比如 dll 提速、modern mode、webpack@5、自動(dòng)化 external、bundler less 等等。

        什么時(shí)候不用 umi?

        如果你,

        • 需要支持 IE 8 或更低版本的瀏覽器
        • 需要支持 React 16.8.0 以下的 React
        • 需要跑在 Node 10 以下的環(huán)境中
        • 有很強(qiáng)的 webpack 自定義需求和主觀意愿
        • 需要選擇不同的路由方案

        Umi 可能不適合你。

        為什么不是?

        [1]create-react-app[2]

        create-react-app 是基于 webpack 的打包層方案,包含 build、dev、lint 等,他在打包層把體驗(yàn)做到了極致,但是不包含路由,不是框架,也不支持配置。所以,如果大家想基于他修改部分配置,或者希望在打包層之外也做技術(shù)收斂時(shí),就會(huì)遇到困難。

        [3]next.js[4]

        next.js 是個(gè)很好的選擇,Umi 很多功能是參考 next.js 做的。要說(shuō)有哪些地方不如 Umi,我覺(jué)得可能是不夠貼近業(yè)務(wù),不夠接地氣。比如 antd、dva 的深度整合,比如國(guó)際化、權(quán)限、數(shù)據(jù)流、配置式路由、補(bǔ)丁方案、自動(dòng)化 external 方面等等一線開(kāi)發(fā)者才會(huì)遇到的問(wèn)題。

        umi3項(xiàng)目初始化

        環(huán)境準(zhǔn)備

        首先得有?node[5],并確保 node 版本是 10.13 或以上。

        推薦使用?yarn?管理 npm 依賴

        本項(xiàng)目使用的版本為 node?v14.17.5?yarn?1.22.15

        腳手架

        桌面新建umi3文件夾, 用vscode打開(kāi), 打開(kāi)vscode終端,

        執(zhí)行?yarn create @umijs/umi-app?創(chuàng)建項(xiàng)目

        安裝依賴?yarn

        啟動(dòng)項(xiàng)目?yarn start

        配置 prettier,eslint, stylelint

        umi 維護(hù)了一個(gè) prettier,eslint,stylelint 的配置文件合集?umi-fabric[6]

        yarn?add?@umijs/fabric?-D
        復(fù)制代碼

        根目錄新建下面三個(gè)文件,刪除.prettierrc文件

        .eslintrc.js.prettierrc.js、.stylelintrc.js

        配置如下

        //.eslintrc.js?配置

        module.exports?=?{
        ??extends:?[require.resolve('@umijs/fabric/dist/eslint')],

        ??//?in?antd-design-pro
        ??globals:?{
        ????ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION:?true,
        ????page:?true,
        ??},

        ??rules:?{
        ????//?your?rules
        ????'prefer-const':?0,
        ??},
        };


        //.prettierrc.js?配置

        const?fabric?=?require('@umijs/fabric')

        module.exports?=?{
        ??...fabric.prettier,
        ??semi:?false,
        }


        //.stylelintrc.js?配置

        const?fabric?=?require('@umijs/fabric')

        module.exports?=?{
        ??...fabric.stylelint,
        }
        復(fù)制代碼

        根目錄新建eslint忽略文件 .eslintignore

        .eslintrc.js
        node_modules
        復(fù)制代碼

        在package.json 里面的lint-staged 新增?"eslint \--fix"

        1634719305(1).png

        最后你的 vscode 要安裝這三個(gè)同名擴(kuò)展插件,這時(shí)候分別去更改 js、less 文件,會(huì)發(fā)現(xiàn)已經(jīng)有風(fēng)格校驗(yàn)了。

        驗(yàn)證

        7d684cab2e5ef8d167c81653582af15.jpg

        修改src/paegs文件夾下的index.tsx文件,新增一個(gè)a變量,有eslint錯(cuò)誤提示,說(shuō)明eslint生效了

        然后再單獨(dú)提交index.tsx這一個(gè)文件

        f87c265f5003a8899498b860baa64ce.png

        會(huì)提示有錯(cuò)誤,無(wú)法提交,說(shuō)明pre-commmit?鉤子生效

        保存時(shí)自動(dòng)格式化代碼

        在vscode設(shè)置 文本編輯器的格式化里面 勾選Format on Save

        1.png

        我的eslint,或者prettier 不生效?

        222.png

        去到終端里的輸出,找到eslint或者prettier 看他們的輸出日志,是否正常。如果有報(bào)錯(cuò),根據(jù)報(bào)錯(cuò)信息處理問(wèn)題

        檢查步驟:

        • 確保安裝umi-fabric
        • 檢查配置文件是否存在
        • vscode 得eslint 和prettier 插件是否下載
        • 確認(rèn)輸出日志,是否有報(bào)錯(cuò)

        pre-commit時(shí)的lint-staged 不生效

        在package.json中 我們配置了如下得代碼

        565.png

        意思是 在代碼commit之前 執(zhí)行prettier格式化代碼和eslint fix 如果你在提交代碼的時(shí)候沒(méi)有生效,請(qǐng)執(zhí)行

        yarn?install?--force
        復(fù)制代碼

        執(zhí)行這個(gè)命令重新拉取依賴

        不生效的原因?

        自己剛開(kāi)始也是各種google,查看文檔,也沒(méi)有找出原因,最后在umi2的一個(gè)issue里面,自己找到了答案。

        原因在于我們初始化git倉(cāng)庫(kù)的順序,如果我們先初始化git倉(cāng)庫(kù) 然后再創(chuàng)建項(xiàng)目,再拉取依賴。是沒(méi)有任何問(wèn)題的。

        如果我們先創(chuàng)建了umi項(xiàng)目,拉去依賴,最后初始化git,提交代碼到git倉(cāng)庫(kù),當(dāng)我們拉去依賴時(shí), 這是就還沒(méi)有.git 就沒(méi)有生成相關(guān)的pre-commit,所以就沒(méi)有生效。所以這時(shí)我們就只需要在重新拉取下依賴就可以了。

        配置css初始化代碼

        為什么要初始化css

        建站老手都知道,這是為了考慮到瀏覽器的兼容問(wèn)題,其實(shí)不同瀏覽器對(duì)有些標(biāo)簽的默認(rèn)值是不同的,如果沒(méi)對(duì)CSS初始化往往會(huì)出現(xiàn)瀏覽器之間的頁(yè)面差異。當(dāng)然,初始化樣式會(huì)對(duì)SEO有一定的影響,但魚(yú)和熊掌不可兼得,但力求影響最小的情況下初始化。

        最簡(jiǎn)單的初始化方法就是:* {padding: 0; margin: 0;}?。有很多人也是這樣寫的。這確實(shí)很簡(jiǎn)單,但有人就會(huì)感到疑問(wèn):*號(hào)這樣一個(gè)通用符在編寫代碼的時(shí)候是快,但如果網(wǎng)站很大,CSS樣式表文件很大,這樣寫的話,他會(huì)把所有的標(biāo)簽都初始化一遍,這樣就大大的加強(qiáng)了網(wǎng)站運(yùn)行的負(fù)載,會(huì)使網(wǎng)站加載的時(shí)候需要很長(zhǎng)一段時(shí)間。

        CSS初始化是指重設(shè)瀏覽器的樣式。不同的瀏覽器默認(rèn)的樣式可能不盡相同,所以開(kāi)發(fā)時(shí)的第一件事可能就是如何把它們統(tǒng)一。如果沒(méi)對(duì)CSS初始化往往會(huì)出現(xiàn)瀏覽器之間的頁(yè)面差異。每次新開(kāi)發(fā)網(wǎng)站或新網(wǎng)頁(yè)時(shí)候通過(guò)初始化CSS樣式的屬性,為我們將用到的CSS或html標(biāo)簽更加方便準(zhǔn)確,使得我們開(kāi)發(fā)網(wǎng)頁(yè)內(nèi)容時(shí)更加方便簡(jiǎn)潔,同時(shí)減少CSS代碼量,節(jié)約網(wǎng)頁(yè)下載時(shí)間。

        Umi 中約定?src/global.css?為全局樣式,如果存在此文件,會(huì)被自動(dòng)引入到入口文件最前面。

        src下面新建global.css,代碼如下

        body,
        ol,
        ul,
        h1,
        h2,
        h3,
        h4,
        h5,
        h6,
        p,
        th,
        td,
        dl,
        dd,
        form,
        fieldset,
        legend,
        input,
        textarea,
        select,
        figure,
        figcaption?{
        ??margin:?0;
        ??padding:?0;
        }

        li?{
        ??list-style-type:?none;
        }
        a?{
        ??text-decoration:?none;
        }

        a:hover?{
        ??text-decoration:?underline;
        }
        img?{
        ??border:?none;
        }
        input?{
        ??outline:?none;
        }

        復(fù)制代碼

        配置文件

        Umi 在?.umirc.ts?或?config/config.ts?中配置項(xiàng)目和插件,支持 es6。

        如果項(xiàng)目的配置不復(fù)雜,推薦在?.umirc.ts?中寫配置;如果項(xiàng)目的配置比較復(fù)雜,可以將配置寫在?config/config.ts?中,并把配置的一部分拆分出去,比如路由配置可以拆分成單獨(dú)的?routes.ts

        推薦兩種配置方式二選一,.umirc.ts?優(yōu)先級(jí)更高。

        我們采用config的方式,刪除.umirc.ts,根目錄新建config文件夾, 在里面新建config.ts

        默認(rèn)內(nèi)容如下

        import?{?defineConfig?}?from?'umi';

        export?default?defineConfig({
        ??nodeModulesTransform:?{
        ????type:?'none',
        ??},
        ??routes:?[
        ????{?path:?'/',?component:?'@/pages/index'?},
        ??],
        ??fastRefresh:?{},
        });
        復(fù)制代碼

        多環(huán)境多配置文件

        可以通過(guò)環(huán)境變量?UMI_ENV?區(qū)分不同環(huán)境來(lái)指定配置。

        為了兼容性,可借助三方工具?cross-env[7]來(lái)設(shè)置環(huán)境變量

        yarn?add?cross-env?--dev
        復(fù)制代碼

        在package.json中的script

        ????"start":?"cross-env?UMI_ENV=dev?umi?dev",
        ????"start:test":?"cross-env?UMI_ENV=test?umi?dev",
        ????"start:prd":?"cross-env?UMI_ENV=prd?umi?dev",
        ????"build":?"cross-env?UMI_ENV=dev?umi?build",
        ????"build:test":?"cross-env?UMI_ENV=test?umi?build",
        ????"build:prd":?"cross-env?UMI_ENV=prd?umi?build",
        復(fù)制代碼

        然后再config文件夾下 新建

        config.dev.ts,config.test.ts,config.prd.ts

        代表開(kāi)發(fā)環(huán)境,測(cè)試環(huán)境,生產(chǎn)環(huán)境的配置文件.

        config.dev.ts

        import?{?defineConfig?}?from?'umi';
        export?default?defineConfig({
        ??define:?{
        ????CurrentEnvironment:?'dev',
        ??},
        });

        復(fù)制代碼

        config.test.ts

        import?{?defineConfig?}?from?'umi';
        export?default?defineConfig({
        ??define:?{
        ????CurrentEnvironment:?'test',
        ??},
        });

        復(fù)制代碼

        config.prd.ts

        import?{?defineConfig?}?from?'umi';
        export?default?defineConfig({
        ??define:?{
        ????CurrentEnvironment:?'prd',
        ??},
        });

        復(fù)制代碼

        CurrentEnvironment?變量代表當(dāng)前的環(huán)境,后面根據(jù)不同的環(huán)境配置不同的請(qǐng)求地址會(huì)用到

        define[8]?用于提供給代碼中可用的變量,定義的變量可以全局拿到

        這時(shí) 執(zhí)行?yarn start:prd,然后去到pages的index.tsx打印CurrentEnvironment.

        b49bd8611d5c6403479a1547ba4bbc6.png

        這時(shí)需要去到根目錄的?typings.d.ts?添加

        //?聲明當(dāng)前的環(huán)境
        declare?const?CurrentEnvironment:?'dev'?|?'test'?|?'prd';
        復(fù)制代碼

        然后報(bào)錯(cuò)消失 控制臺(tái)打印如下

        1634721237(1).png

        這時(shí) 重新執(zhí)行yanr start:test?控制臺(tái)打印如下

        11.png

        環(huán)境變量和多環(huán)境多配置 成功

        **注意點(diǎn)**:

        config.ts作為配置文件時(shí),記得刪除.umirc.ts?不然config.ts不會(huì)生效。

        自定義環(huán)境變量

        如果我們想自定義一個(gè)環(huán)境變量,REACT_APP_ENV. 同樣我們可以在package.json里面設(shè)置

        1634783299(1).png

        然后我們要這樣拿到這個(gè)變量呢?

        首先 我們要在config.ts?的?define?配置

        define:?{
        ????REACT_APP_ENV:?process.env.REACT_APP_ENV,
        },
        復(fù)制代碼

        然后再在根目錄的?typings.d.ts?定義

        declare?const?REACT_APP_ENV:?string;
        復(fù)制代碼

        這樣就可以以在全局中拿到和使用?REACT_APP_ENV這個(gè)環(huán)境變量了.

        可以在任意組件 直接打印

        ?console.log('自定義環(huán)境變量',?REACT_APP_ENV);
        復(fù)制代碼

        系統(tǒng)自帶的環(huán)境變量

        官方提供的環(huán)境變量[9]

        怎么使用?

        在根目錄新建.env?環(huán)境變量配置文件

        然后寫入

        PORT=3000??//?表示啟動(dòng)的端口號(hào)為3000
        COMPRESS?=?none??//?不壓縮?CSS?和?JS
        復(fù)制代碼

        還有一些環(huán)境變量 不能配在?.env?中,只能在命令行里添加

        比如?FORK_TS_CHECKER?默認(rèn)不開(kāi)啟 TypeScript 類型檢查,值為?1?時(shí)啟用。

        "start":?"cross-env?FORK_TS_CHECKER=1?UMI_ENV=dev?umi?dev",
        復(fù)制代碼

        請(qǐng)求的封裝

        src文件夾下新建?request文件夾 新建request.ts

        request.ts

        /**
        ?*?網(wǎng)絡(luò)請(qǐng)求工具?封裝umi-request
        ?*?更詳細(xì)的?api?文檔:?https://github.com/umijs/umi-request
        ?*/


        import?{?extend?}?from?'umi-request';
        import?type?{?RequestOptionsInit?}?from?'umi-request';
        import?{?notification?}?from?'antd';

        //?codeMessage僅供參考?具體根據(jù)和后端協(xié)商,在詳細(xì)定義.
        const?codeMessage?=?{
        ??200:?'服務(wù)器成功返回請(qǐng)求的數(shù)據(jù)。',
        ??400:?'發(fā)出的請(qǐng)求有錯(cuò)誤,服務(wù)器沒(méi)有進(jìn)行新建或修改數(shù)據(jù)的操作。',
        ??500:?'服務(wù)器發(fā)生錯(cuò)誤,請(qǐng)檢查服務(wù)器。',
        };
        type?mapCode?=?200?|?400?|?500;

        /**
        ?*?錯(cuò)誤異常處理程序
        ?*/

        const?errorHandler?=?(error:?{?response:?Response?}):?Response?=>?{
        ??const?{?response?}?=?error;
        ??if?(response?&&?response.status)?{
        ????let?errorText?=?codeMessage[response.status?as?mapCode]?||?response.statusText;
        ????const?{?status,?url?}?=?response;
        ????response
        ???????.clone()
        ???????.json()
        ???????.then((res)?=>?{
        ????????//?后端返回錯(cuò)誤信息,就用后端傳回的
        ????????errorText?=?res.msg???res.msg?:?errorText;
        ????????notification.error({
        ??????????message:?`請(qǐng)求錯(cuò)誤?${status}:?${url}`,
        ??????????description:?errorText,
        ????????});
        ??????});
        ??}?else?if?(!response)?{
        ????notification.error({
        ??????description:?'您的網(wǎng)絡(luò)發(fā)生異常,無(wú)法連接服務(wù)器',
        ??????message:?'網(wǎng)絡(luò)異常',
        ????});
        ??}
        ??return?response;
        };

        /**
        ?*?配置request請(qǐng)求時(shí)的默認(rèn)參數(shù)
        ?*/

        const?request?=?extend({
        ??errorHandler,?//?默認(rèn)錯(cuò)誤處理
        ??credentials:?'include',?//?默認(rèn)請(qǐng)求是否帶上cookie
        });

        //?根據(jù)不同的開(kāi)發(fā)環(huán)境,配置請(qǐng)求前綴
        interface?ApiPrefix?{
        ??dev:?string;
        ??test:?string;
        ??prd:?string;
        }
        const?apiPreFix:?ApiPrefix?=?{
        ??dev:?'http://120.55.193.14:3030/',
        ??test:?'http://120.55.193.14:3030/',
        ??prd:?'http://120.55.193.14:3030/',
        };
        //?request攔截器,?攜帶token,以及根據(jù)環(huán)境,配置不同的請(qǐng)求前綴
        request.interceptors.request.use((url:?string,?options:?RequestOptionsInit)?=>?{
        ??//?不攜帶token的請(qǐng)求數(shù)組
        ??let?notCarryTokenArr:?string[]?=?[];
        ??if?(notCarryTokenArr.includes(url))?{
        ????return?{
        ??????url:?`${apiPreFix[CurrentEnvironment]}${url}`,
        ??????options,
        ????};
        ??}
        ??//?給每個(gè)請(qǐng)求帶上token
        ??let?token?=?localStorage.getItem('tokens')?||?'';
        ??let?headers?=?{
        ????Authorization:?`Bearer?${token}`,
        ??};
        ??return?{
        ????url:?`${apiPreFix[CurrentEnvironment]}${url}`,
        ????options:?{?...options,?interceptors:?true,?headers?},
        ??};
        });

        /**
        ?*?@url?請(qǐng)求的url
        ?*?@parameter?上傳的參數(shù)
        ?*/


        //?封裝的get,post.put,delete請(qǐng)求
        const?get?=?async?(url:?string,?parameter?:?Record):?Promise?=>?{
        ??try?{
        ????const?res?=?await?request(url,?{?method:?'get',?params:?parameter?});
        ????return?res;
        ??}?catch?(error)?{
        ????console.error(error);
        ??}
        };
        const?deletes?=?async?(url:?string,?parameter?:?Record):?Promise?=>?{
        ??try?{
        ????const?res?=?await?request(url,?{?method:?'delete',?params:?parameter?});
        ????return?res;
        ??}?catch?(error)?{
        ????console.error(error);
        ??}
        };
        const?post?=?async?(url:?string,?parameter?:?Record):?Promise?=>?{
        ??try?{
        ????const?res?=?await?request(url,?{?method:?'post',?data:?parameter?});
        ????return?res;
        ??}?catch?(error)?{
        ????console.error(error);
        ??}
        };
        const?put?=?async?(url:?string,?parameter?:?Record):?Promise?=>?{
        ??try?{
        ????const?res?=?await?request(url,?{?method:?'put',?data:?parameter?});
        ????return?res;
        ??}?catch?(error)?{
        ????console.error(error);
        ??}
        };

        export?default?{
        ??get,
        ??post,
        ??put,
        ??deletes,
        };
        復(fù)制代碼

        這里封裝了umi-request,統(tǒng)一處理了接口錯(cuò)誤,請(qǐng)求攔截器攜帶token等.最后在配合useRequest 非常的好用.

        umi中使用dva

        介紹

        包含以下功能,

        • 內(nèi)置 dva,默認(rèn)版本是?^2.6.0-beta.20,如果項(xiàng)目中有依賴,會(huì)優(yōu)先使用項(xiàng)目中依賴的版本。
        • 約定式的 model 組織方式,不用手動(dòng)注冊(cè) model
        • 文件名即 namespace,model 內(nèi)如果沒(méi)有聲明 namespace,會(huì)以文件名作為 namespace
        • 內(nèi)置 dva-loading,直接 connect?loading?字段使用即可
        • 支持 immer,通過(guò)配置?immer?開(kāi)啟

        約定式的 model 組織方式

        符合以下規(guī)則的文件會(huì)被認(rèn)為是 model 文件,

        • src/models?下的文件
        • src/pages?下,子目錄中 models 目錄下的文件
        • src/pages?下,所有 model.ts 文件(不區(qū)分任何字母大小寫)

        實(shí)際使用

        比如在src下新建 models文件夾,里面新建test.ts

        test.ts

        import?type?{?Effect,?Reducer,?Subscription?}?from?'umi';?//?映入umi?定義好的ts類型
        import?axios?from?'../request/request';?//?引入封裝好的網(wǎng)絡(luò)請(qǐng)求

        //?state?接口
        export?interface?TextModelState?{
        ??name?:?string;
        ??testData?:?string;
        }

        //?test?model接口
        export?interface?TextModelType?{
        ??namespace:?'testModel';
        ??state:?TextModelState;
        ??effects:?{
        ????query:?Effect;
        ??};
        ??reducers:?{
        ????save:?Reducer;
        ????msg:?Reducer;
        ??};
        ??subscriptions?:?{?setup:?Subscription?};
        }

        const?IndexModel:?TextModelType?=?{
        ??namespace:?'testModel',
        ??state:?{
        ????name:?'初始名字',
        ????testData:?'初始testData',
        ??},
        ??effects:?{
        ????*query(action,?{?call,?put?})?{
        ??????const?getDataTest?=?async?()?=>?{
        ????????const?data?=?await?axios.get('test');
        ????????return?data;
        ??????};
        ??????let?testData?=?yield?call(getDataTest);
        ??????yield?put({
        ????????type:?'msg',
        ????????data:?{?testData:?testData?.msg?},
        ??????});
        ????},
        ??},

        ??reducers:?{
        ????save(state)?{
        ??????return?{
        ????????...state,
        ????????name:?'jimmy',
        ??????};
        ????},
        ????msg(state,?action)?{
        ??????return?{
        ????????...state,
        ????????testData:?action?.data?.testData,
        ????????testData2:?action?.data?.testData2,
        ??????};
        ????},
        ??},
        };
        export?default?IndexModel;

        復(fù)制代碼

        在src/pages下的index.tsx中使用

        index.tsx

        import?type?{?Effect,?Reducer,?Subscription?}?from?'umi';?//?引入umi?定義好的ts類型
        import?axios?from?'../request/request';?//?引入封裝好的網(wǎng)絡(luò)請(qǐng)求

        //?state?接口
        export?interface?TextModelState?{
        ??name?:?string;
        ??testData?:?string;
        }

        //?test?model接口
        export?interface?TextModelType?{
        ??namespace:?'testModel';
        ??state:?TextModelState;
        ??effects:?{
        ????query:?Effect;
        ??};
        ??reducers:?{
        ????save:?Reducer;
        ????msg:?Reducer;
        ??};
        ??subscriptions?:?{?setup:?Subscription?};
        }

        const?IndexModel:?TextModelType?=?{
        ??namespace:?'testModel',
        ??state:?{
        ????name:?'初始名字',
        ????testData:?'初始testData',
        ??},
        ??effects:?{
        ????*query(action,?{?call,?put?})?{
        ??????const?getDataTest?=?async?()?=>?{
        ????????const?data?=?await?axios.get('test');
        ????????return?data;
        ??????};
        ??????let?testData?=?yield?call(getDataTest);
        ??????yield?put({
        ????????type:?'msg',
        ????????data:?{?testData:?testData?.msg?},
        ??????});
        ????},
        ??},

        ??reducers:?{
        ????save(state)?{
        ??????return?{
        ????????...state,
        ????????name:?'jimmy',
        ??????};
        ????},
        ????msg(state,?action)?{
        ??????return?{
        ????????...state,
        ????????testData:?action?.data?.testData,
        ????????testData2:?action?.data?.testData2,
        ??????};
        ????},
        ??},
        };
        export?default?IndexModel;
        復(fù)制代碼

        mfsu

        啟用 mfsu 后,熱啟動(dòng)得到?**10 倍**?提升;熱更新提升?**50%** ?以上!

        如何啟用

        在 config/config.ts 中添加?mfsu:{}

        項(xiàng)目源代碼

        請(qǐng)點(diǎn)擊我[10]

        和兩個(gè)小伙伴一起,會(huì)根據(jù)實(shí)際運(yùn)用中出現(xiàn)的問(wèn)題或者沒(méi)有考慮完善的地方,持續(xù)的更新迭代.如有問(wèn)題,歡迎提Issue或者在評(píng)論區(qū)留言

        FAQ

        umi?不是內(nèi)部或外部命令

        image.png

        解決辦法

        執(zhí)行?yarn global bin?拿到 bin 路徑。然后把這個(gè)路徑添加到環(huán)境變量里面的系統(tǒng)變量的path里面

        如果還是不行,執(zhí)行

        yarn?global?add?umi
        復(fù)制代碼

        如遇到更多問(wèn)題,請(qǐng)查考

        官方FAQ[11]

        官方倉(cāng)庫(kù)的issue[12]

        大家還是要把官方文檔看兩遍哦,一些基礎(chǔ),簡(jiǎn)單的知識(shí)本文章沒(méi)有涉及.

        最后

        如果后續(xù)自己還踩了坑,會(huì)繼續(xù)更新,如果有什么錯(cuò)誤或者建議,歡迎評(píng)論區(qū)留言,如果覺(jué)得文章對(duì)你有幫助,就點(diǎn)個(gè)贊支持一下唄。


        關(guān)于本文

        作者:Jimmy_kiwi

        https://juejin.cn/post/7021358536504393741

        The End

        歡迎自薦投稿到《前端技術(shù)江湖》,如果你覺(jué)得這篇內(nèi)容對(duì)你挺有啟發(fā),記得點(diǎn)個(gè)?「在看」


        點(diǎn)個(gè)『在看』支持下?


        瀏覽 69
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
          
          

            1. 女主被爆羞羞视频 | 精品动漫一区二区三区的观看方式 | 无码任你躁久久久久久小说 | 色噜噜国产在线观看 | 红桃色av |