Taro多端開發(fā)權(quán)威指南(小程序、H5與App高效開發(fā)實戰(zhàn))_第1頁
Taro多端開發(fā)權(quán)威指南(小程序、H5與App高效開發(fā)實戰(zhàn))_第2頁
Taro多端開發(fā)權(quán)威指南(小程序、H5與App高效開發(fā)實戰(zhàn))_第3頁
Taro多端開發(fā)權(quán)威指南(小程序、H5與App高效開發(fā)實戰(zhàn))_第4頁
Taro多端開發(fā)權(quán)威指南(小程序、H5與App高效開發(fā)實戰(zhàn))_第5頁
已閱讀5頁,還剩245頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)

文檔簡介

Taro多端開發(fā)權(quán)威指南小程序、H5與App高效開發(fā)實戰(zhàn)目錄TOC\h\h第1章初識Taro\h1.1Taro介紹\h1.1.1簡介\h1.1.2特性\h1.1.3TaroUI\h1.1.4其他\h1.2ES6常用語法簡介\h1.2.1變量定義新方式——let、const\h1.2.2告別字符串拼接——模板字符串\h1.2.3優(yōu)雅獲取數(shù)組或?qū)ο笾械闹怠鈽?gòu)賦值\h1.2.4二次元函數(shù)——箭頭函數(shù)\h1.2.5異步處理——Promise\h1.2.6面向?qū)ο缶幊獭猚lass\h1.2.7模塊化——import、export\h1.3開發(fā)環(huán)境及工具介紹\h1.3.1安裝Taro腳手架工具\h1.3.2初始化項目\h1.3.3運行項目\h1.3.4打包項目\h1.3.5Taro腳手架命令\h1.4規(guī)范約定\h1.4.1項目組織\h1.4.2JavaScript/TypeScript書寫規(guī)范\h1.4.3組件及JSX書寫規(guī)范\h1.5本章小結(jié)\h第2章Taro基礎(chǔ)\h2.1JSX\h2.1.1JSX簡介\h2.1.2JSX語法\h2.2組件化\h2.2.1初識組件\h2.2.2組件定義\h2.2.3props\h2.2.4state\h2.2.5樣式\h2.3組件生命周期\h2.3.1組件掛載\h2.3.2組件更新\h2.3.3組件卸載\h2.4事件處理\h2.5路由功能\h2.6實戰(zhàn)案例:受控與非受控Input組件\h2.7本章小結(jié)\h第3章Taro進階\h3.1組件設(shè)計\h3.2組件通信\h3.2.1父子組件通信\h3.2.2兄弟組件通信\h3.2.3更復(fù)雜的組件通信\h3.3服務(wù)端通信\h3.3.1Taro.request\h3.3.2請求終止\h3.3.3請求攔截器\h3.4使用Ref\h3.5本章小結(jié)\h第4章集中狀態(tài)管理\h4.1Redux\h4.1.1Redux設(shè)計理念\h4.1.2在Taro中使用Redux\h4.1.3Redux案例\h4.2MobX\h4.2.1MobX設(shè)計理念\h4.2.2在Taro中使用MobX\h4.3本章小結(jié)\h第5章Hooks\h5.1Hooks簡介\h5.1.1class組件的不足\h5.1.2Hooks概覽\h5.1.3Hooks規(guī)則\h5.2Hooks基礎(chǔ)\h5.2.1useState\h5.2.2useEffect\h5.2.3useReducer\h5.2.4useCallback\h5.2.5useMemo\h5.2.6useRef\h5.2.7useContext\h5.2.8其他Hooks\h5.3自定義Hooks\h5.4本章小結(jié)\h第6章多端開發(fā)\h6.1編譯配置與約定\h6.1.1編譯配置\h6.1.2設(shè)計稿與尺寸單位約定\h6.2多端開發(fā)方案\h6.2.1內(nèi)置環(huán)境變量\h6.2.2統(tǒng)一接口的多端文件\h6.2.3指定解析node_modules包中的多端文件\h6.3多端同步調(diào)試與打包\h6.4本章小結(jié)\h第7章TaroUI\h7.1安裝及使用\h7.1.1快速上手\h7.1.2自定義主題\h7.2組件介紹\h7.3本章小結(jié)\h第8章插件機制\h8.1插件機制簡介\h8.2插件使用\h8.3自定義插件\h8.3.1插件結(jié)構(gòu)\h8.3.2插件使用場景\h8.3.3插件環(huán)境變量\h8.3.4插件方法\h8.4本章小結(jié)\h第9章性能優(yōu)化與原理剖析\h9.1性能優(yōu)化\h9.1.1Prerender\h9.1.2虛擬列表\h9.1.3組件更新條件\h9.2Taro框架原理\h9.2.1Taro框架結(jié)構(gòu)分析\h9.2.2Taro編譯原理\h9.2.3Taro運行時\h9.3Taro3.x原理概述\h9.4本章小結(jié)\h第10章多端開發(fā)環(huán)境搭建\h10.1微信小程序開發(fā)環(huán)境搭建\h10.2支付寶小程序開發(fā)環(huán)境搭建\h10.3ReactNative開發(fā)環(huán)境搭建\h10.3.1在macOS系統(tǒng)下搭建iOS開發(fā)環(huán)境\h10.3.2在macOS系統(tǒng)下搭建Android開發(fā)環(huán)境\h10.3.3在Windows系統(tǒng)下搭建Android開發(fā)環(huán)境\h10.3.4使用Taro開發(fā)iOS應(yīng)用\h10.3.5使用Taro開發(fā)Android應(yīng)用\h10.4本章小結(jié)\h第11章閑置換App開發(fā)實踐\h11.1項目介紹\h11.1.1項目背景\h11.1.2項目需求\h11.1.3項目核心功能設(shè)計\h11.1.4項目架構(gòu)設(shè)計\h11.1.5項目接口mock\h11.2基礎(chǔ)功能開發(fā)\h11.2.1通用請求庫封裝\h11.2.2引入dva\h11.2.3定義請求服務(wù)\h11.2.4為H5配置請求代理\h11.3自定義導(dǎo)航器\h11.3.1需求分析\h11.3.2微信小程序端開發(fā)\h11.3.3H5端開發(fā)\h11.3.4ReactNative端開發(fā)\h11.4首頁開發(fā)\h11.4.1搜索組件\h11.4.2瀑布流圖片組件\h11.4.3輪播圖組件\h11.4.4數(shù)據(jù)聯(lián)調(diào)\h11.5消息頁開發(fā)\h11.5.1定義底部導(dǎo)航\h11.5.2消息列表頁開發(fā)\h11.5.3聊天頁面開發(fā)\h11.6商品詳情頁開發(fā)\h11.7項目優(yōu)化與發(fā)布\h11.7.1項目優(yōu)化\h11.7.2項目打包發(fā)布\h11.8本章小結(jié)\h第12章?lián)肀aro3\h12.1Taro演進歷程\h12.1.1Taro1.x\h12.1.2Taro2.x\h12.1.3Taro3.x\h12.2使用Taro3\h12.2.1React模板\h12.2.2Vue模板\h12.3本章小結(jié)第1章初識Taro如今,小程序百花爭艷,好一派繁華;Web、原生應(yīng)用開發(fā)“踩雷”不斷,著實讓人焦慮。我們前端人不停探索,不停找尋多端開發(fā)方案,由此催生出了很多優(yōu)秀框架,其中就有Taro。使用Taro,你只需編寫一次代碼就可以編譯生成各端應(yīng)用,真正提高了小程序、Web開發(fā)效率。另外,由于成書時,Taro3.x不支持ReactNative端開發(fā),所以書中的知識及實例以2.2.13版本為準(zhǔn)。如果你想了解更多關(guān)于Taro版本演進與Taro3.x的知識,可查看第12章的詳細介紹。1.1Taro介紹1.1.1簡介Taro是一套遵循React語法規(guī)范的多端開發(fā)解決方案,甚至在Taro3.0及以上版本可以選用Vue、React或Nerv作為開發(fā)規(guī)范。Taro遵循React語法,但和React并沒有直接關(guān)系。Taro底層使用了京東團隊開發(fā)的Nerv框架,該框架語法接近React。面對微信小程序、京東小程序、百度小程序、支付寶小程序、字節(jié)跳動小程序、快應(yīng)用、H5、ReactNative開發(fā),我們深感疲憊,假如只編寫一套代碼就能適配這里列舉的各種端,豈不快哉?不妨,先想象一下writeonce,runanywhere,是多么令人神往。1.1.2特性1.類似React的語法風(fēng)格Taro遵循React語法規(guī)范,它采用與React一致的組件化思想、組件生命周期、JSX語法等,如此,將開發(fā)學(xué)習(xí)的成本降到最低。只要你使用過React,就可以使用Taro來快速開發(fā)多端應(yīng)用,從而降低學(xué)習(xí)成本,提升開發(fā)體驗。Taro基本用法的代碼示例如下:上面這段代碼展示了Taro構(gòu)建多端應(yīng)用的基本寫法,其中包括頁面元素、頁面數(shù)據(jù)、組件生命周期。遺憾的是,因為早期Taro架構(gòu)限制,無法完全支持React所有的JSX語法。為了解決這一問題,Taro制定了對應(yīng)的語法規(guī)范,關(guān)于規(guī)范約定的詳細內(nèi)容請參閱1.4節(jié)的內(nèi)容。2.快速開發(fā)小程序Taro立足于微信小程序開發(fā)。眾所周知,微信小程序的開發(fā)體驗不太友好,如經(jīng)常會被提及的這些問題:·小程序中無法使用npm來做第三方庫的管理。·無法使用新的ES規(guī)范。針對這些問題,Taro改良并提供了以下優(yōu)秀特性:·支持使用npm/yarn安裝管理第三方依賴?!ぶС质褂肊S7/ES8甚至更新的ES規(guī)范,一切都可以自行進行配置?!ぶС质褂肅SS預(yù)編譯器,如Sass、Less等。·支持使用Redux、MobX等進行狀態(tài)管理?!ば〕绦駻PI優(yōu)化,異步APIPromise化等。3.支持多端開發(fā)轉(zhuǎn)化Taro方案是在實踐中總結(jié)出的快速打造多端開發(fā)應(yīng)用的解決方案。目前通過Taro編寫的代碼能夠編譯為可以運行在微信/京東/百度/支付寶/字節(jié)跳動/QQ小程序的快應(yīng)用、H5及原生應(yīng)用(ReactNative)。1.1.3TaroUITaro解決了跨端開發(fā)規(guī)范的問題,但依然存在其他問題,如界面一致性。經(jīng)過社區(qū)不斷完善,催生出了TaroUI——提供多端界面風(fēng)格統(tǒng)一方案。其主要特性如下:·基于Taro開發(fā)的UI組件。·一套組件可以在微信/支付寶/百度小程序、H5多端適配運行(ReactNative端暫不支持)?!ぬ峁﹥?yōu)化的API,可靈活地使用組件。1.1.4其他學(xué)習(xí)是一個枯燥的過程,在學(xué)習(xí)Taro的過程中,無論你有任何問題或者建議,都可以訪問Taro官網(wǎng)查找資料或者提出相關(guān)建議。如果你經(jīng)常使用GitHub,也可搜索awesome-taro查看更多學(xué)習(xí)資源。1.2ES6常用語法簡介ECMAScript是JavaScript語言標(biāo)準(zhǔn),ECMAScript又有多個版本,目前我們使用最多的版本是ECMAScript6,簡稱ES6,使用最新語法能夠帶給我們更順暢、更高效的開發(fā)體驗。正因如此,在學(xué)習(xí)Taro或者React之前,都應(yīng)該好好學(xué)習(xí)一下ES6甚至更新的語法規(guī)范,所以本節(jié)先整體介紹項目開發(fā)中使用最多的一些ES6語法。1.2.1變量定義新方式——let、const曾經(jīng),我們只知道var可以聲明一個變量,并且在項目中大量使用。不知道你是否遇到過類似以下的問題。1.聲明一個變量后,在下面的代碼中又聲明了一次,程序依然能夠運行以上代碼在正常情況下的表現(xiàn)差強人意,但如果我們現(xiàn)在在做圓周長的計算,定義了一個變量表示圓周率π,不幸的是同事也使用了這個變量名。在理想情況下,我們這樣定義變量:如果同事在開發(fā)過程中,也定義了相同的變量名,則會出錯。例如:在這個需求里,任何時候都不希望PI的值發(fā)生改變,這樣的值在程序中被稱為常量,在ES6中使用const聲明即可。如果在后面的代碼中,const聲明的變量值被修改,則會拋出錯誤,從而提示開發(fā)者。2.定義變量前使用這個變量,不會報錯,而是會告訴你它是undefined這個問題在面試中也會經(jīng)常被問及,原因是var聲明的變量會被提升至作用域頂端,我們把這個特性叫作變量提升。這個特性會在開發(fā)過程中引入很多問題,因此不建議使用,我們可以使用let或const聲明變量來規(guī)避這個問題。3.作用域問題關(guān)于作用域問題,有一個很經(jīng)典的例子。我們通常使用setTimeout定時器來定義一個期望在未來執(zhí)行的操作,代碼如下:執(zhí)行以上代碼,我們期望在1s后,打印從0到4這5個數(shù)字,但最終輸出的結(jié)果卻是5個5,為什么呢?其實問題出在作用域上,我們可以使用let聲明變量,從而生成一個暫時性死區(qū),來解決這個問題。代碼示例如下:1.2.2告別字符串拼接——模板字符串模板字符串是對字符串的增強,使用模板字符串替代普通字符串拼接能提高代碼可讀性。模板字符串使用反引號(`)標(biāo)識,除了實現(xiàn)字符串拼接,還能在字符串中使用表達式或者已定義的變量,進一步增強字符串能力。例如:1.2.3優(yōu)雅獲取數(shù)組或?qū)ο笾械闹怠鈽?gòu)賦值ES6獲取已定義數(shù)組或?qū)ο笾械膶傩愿憬?,以前在編寫代碼時,獲取數(shù)組或?qū)ο笾械闹档姆绞饺缦拢菏褂媒鈽?gòu)賦值,可以提升代碼的可讀性。例如:深層結(jié)構(gòu)的數(shù)組或?qū)ο笠粯涌捎?。例如:rest元素或?qū)傩越鈽?gòu)賦值。例如:1.2.4二次元函數(shù)——箭頭函數(shù)箭頭函數(shù)可以更方便快捷地創(chuàng)建一個函數(shù),并且箭頭函數(shù)中的this指向函數(shù)定義時所在的上下文環(huán)境,規(guī)避this指向偏移發(fā)生的問題。值得一提的是,不能使用箭頭函數(shù)定義構(gòu)造器。例如:如果函數(shù)體包含多條語句,就需要使用大括號將代碼括起來,并使用return返回函數(shù)值。例如:1.2.5異步處理——Promise前端開發(fā)時常伴隨異步處理,在過去很長一段時間里,都是使用回調(diào)函數(shù)處理異步操作。假設(shè)我們現(xiàn)在停頓一秒計算1+2得到結(jié)果3,而后停頓一秒計算3+4,如果使用回調(diào)函數(shù),可能需要這樣編寫:回調(diào)函數(shù)嵌套問題如此可見一斑,這個問題叫作回調(diào)地獄。為了解決上述問題,ES6引入了可讀性更高的特性支持異步處理,那就是Promise。Promise允許使用鏈?zhǔn)秸{(diào)用方式處理異步隊列。使用Promise重寫上述操作,示例如下:這樣,嵌套的問題是不是解決了,代碼的可讀性是不是更高了?如果再使用async,就更易讀了,示例如下:有了這些語法特性,更方便處理異步操作,使用Taro開發(fā)項目時也會經(jīng)常用到這些語法。1.2.6面向?qū)ο缶幊獭猚lass以前的JavaScript面向?qū)ο缶幊滩患兇猓珽S6引入了類的概念,是原型繼承的另一種書寫形式。代碼示例如下:有了類的概念,就可以輕松實現(xiàn)繼承,例如現(xiàn)在有一個類表示人,我們需要在這個類中派生出一個代表女性的類,使用extends關(guān)鍵字即可輕松實現(xiàn),代碼示例如下:1.2.7模塊化——import、exportES6實現(xiàn)了模塊化標(biāo)準(zhǔn),可以使用export導(dǎo)出模塊,import導(dǎo)入模塊。例如:以上介紹的相關(guān)內(nèi)容是我們在使用Taro開發(fā)小程序過程中經(jīng)常會使用的ES6語法,如果你想了解更多關(guān)于ES6的語法知識,可自行查閱相關(guān)資料學(xué)習(xí)。1.3開發(fā)環(huán)境及工具介紹Taro項目開發(fā)依賴Node.js環(huán)境,并且要求Node.js版本高于8.0.0,Taro允許使用大多npm中的庫,支持更友好的第三方依賴管理。如果你剛接觸Taro,那么推薦使用Taro提供的腳手架工具創(chuàng)建項目,同時該工具提供了很多功能,譬如診斷依賴、創(chuàng)建模塊、更新包、打包構(gòu)建等。我們就從安裝Taro腳手架開始吧!1.3.1安裝Taro腳手架工具你可以選用npm或者Yarn全局安裝@tarojs/cli,或者使用npx。不過由于Node.js版本限制等問題,推薦使用nvm這一工具來管理Node.js版本。使用npm全局安裝Taro腳手架:使用Yarn全局安裝Taro腳手架:安裝過程可能會提示Sass相關(guān)依賴安裝錯誤,這時請終止,然后手動安裝mirror-config-china后重試。安裝命令如下:1.3.2初始化項目上一節(jié)已經(jīng)成功安裝Taro腳手架工具,現(xiàn)在只需一行命令就能創(chuàng)建出基礎(chǔ)Taro項目了,命令如下:如果你的npm版本大于5.2,則可以直接使用npx創(chuàng)建項目:項目模板及相關(guān)配置文件創(chuàng)建完成以后,Taro會自動安裝項目中所需要的相關(guān)依賴。為了提升安裝速度,Taro內(nèi)部會為我們按照Yarn、cnpm、npm的順序檢測并選擇更快的方式去安裝依賴。如果在依賴安裝過程中出現(xiàn)錯誤導(dǎo)致安裝終止,則可以進入項目的根目錄嘗試手動安裝。1.3.3運行項目Taro開發(fā)環(huán)境的啟動命令較多,分別對應(yīng)不同端的代碼編譯與調(diào)試,但是為了更方便記憶與語義化,Taro定義了相對一致的開發(fā)環(huán)境啟動命令,以npm運行命令為例,如下表所示。通過以上命令,可以將Taro項目編譯為不同端開發(fā)環(huán)境的代碼。這時,只需要使用各端(除了H5)對應(yīng)的開發(fā)工具,打開編譯生成的項目文件,即可預(yù)覽調(diào)試。以微信小程序為例:(1)運行針對微信小程序的編譯命令:npmrundev:weapp。(2)使用微信小程序開發(fā)工具,打開該項目目錄下的dist文件夾,即可在微信小程序開發(fā)者工具中進行預(yù)覽與調(diào)試。如果你需要同時調(diào)試預(yù)覽多端應(yīng)用,則需要修改項目下的config/index.js文件,配置outputRoot參數(shù):注:Taro1.3.5+支持該配置,請確保項目中各端打包與編譯相關(guān)的依賴版本和@tarojs/cli版本一致。1.3.4打包項目Taro的打包命令同樣有多個,也分別對應(yīng)不同端的線上環(huán)境代碼生成。為了方便記憶與語義化,Taro定義了相對一致的打包線上環(huán)境的代碼命令,以npm為例,如下表所示。通過以上命令,可以將Taro項目編譯為不同端線上環(huán)境的代碼,這時只需要使用各端(除了H5)對應(yīng)的開發(fā)工具發(fā)布項目即可。打包生成線上環(huán)境的代碼相較運行本地開發(fā)環(huán)境的代碼,做了更多優(yōu)化相關(guān)的處理,例如JavaScript代碼壓縮丑化等。1.3.5Taro腳手架命令Taro腳手架提供了很多功能輔助我們開發(fā),可使用taro--help查看Taro腳手架工具的相關(guān)提示。這里給大家講解開發(fā)過程中常使用的幾個命令,更多命令可前往Taro官網(wǎng)查看學(xué)習(xí)。1.更新——update該命令用來更新項目中的Taro相關(guān)依賴或者更新自身的腳手架工具。更新項目依賴:如果用以上方法更新項目依賴失敗,則可嘗試修改package.json文件指定對應(yīng)的依賴版本,然后使用npm或Yarn手動安裝。更新腳手架:注:以上[version]為選填項,通過執(zhí)行對應(yīng)的版本號,安裝或更新至對應(yīng)的版本。2.環(huán)境及依賴信息——info該命令用來檢測Taro環(huán)境及依賴的版本等信息,從而方便開發(fā)者查看項目環(huán)境及依賴,更便捷地排查因開發(fā)環(huán)境引起的問題。用法如下:命令執(zhí)行完畢,會打印出項目的相關(guān)信息,示例如下:這樣一來,我們可以發(fā)現(xiàn)當(dāng)前使用的Taro腳手架工具版本為2.2.4。但項目中的依賴版本卻是2.1.6,此時需要更新項目依賴,以保證與Taro腳手架工具版本一致,更新命令為:3.項目診斷——doctor該命令可以診斷項目的依賴、設(shè)置、結(jié)構(gòu)及代碼的規(guī)范是否存在問題,診斷結(jié)束后會嘗試給出對應(yīng)問題的解決方案。使用示例如下:1.4規(guī)范約定我們提到Taro和React并沒有直接聯(lián)系,Taro支持JSX等語法規(guī)范得益于Nerv框架,而Nerv與React支持的語法特性略有偏差,因此開發(fā)之前我們約法三章,以規(guī)避一些開發(fā)過程中可能遇到的問題。1.4.1項目組織項目組織有很多方案,以下所列建議為最佳實踐方案。1.文件組織所有項目的源碼都放在項目的根目錄src下,項目所需的最基本文件包括入口文件和頁面文件?!と肟谖募閍pp.js?!ろ撁嫖募ㄗh放置在src/pages目錄下。一個可靠的Taro項目可以按照如下方式進行組織:2.文件命名與文件后綴名(1)在Taro項目中,普通JavaScript或TypeScript文件以小寫字母命名,多個單詞之間以下畫線連接,如util.js、util_helper.js。(2)在Taro項目中,組件文件命名遵循Pascal命名法,如ReservationCard.jsx。(3)在Taro項目中,普通JavaScript或TypeScript文件以.js或者.ts為文件后綴名。(4)在Taro項目中,組件以.jsx或者.tsx為文件后綴名。這不是強制約束,只是作為一個實踐的建議。如果你希望組件以.js或者.ts為文件后綴名,也依然可行。1.4.2JavaScript/TypeScript書寫規(guī)范關(guān)于JavaScript/TypeScript書寫規(guī)范,可以使用Eslint做代碼規(guī)范檢查。在項目創(chuàng)建時,Taro就已經(jīng)創(chuàng)建了.eslintrc文件并安裝了Eslint,你在開發(fā)過程中遵循提示即可。若Taro創(chuàng)建的.eslintrc文件中定義的規(guī)范不能完全滿足你的需求,你也可以查閱Eslint配置文檔,根據(jù)團隊制定的規(guī)范,配置規(guī)范約定。以下是.eslintrc配置片段:1.4.3組件及JSX書寫規(guī)范·使用兩個空格進行縮進,不要混合使用空格與制表符作為縮進?!SX屬性均使用單引號。·多個屬性,多行書寫,每個屬性占用一行,標(biāo)簽結(jié)束另起一行?!ぎ?dāng)標(biāo)簽沒有子元素時,始終使用自閉合標(biāo)簽?!そK始在自閉合標(biāo)簽前面添加一個空格?!傩悦Q始終使用駝峰式命名法?!び美ㄌ柊嘈蠮SX標(biāo)簽?!aro組件中包含類靜態(tài)屬性、類屬性、生命周期等類成員,其書寫順序最好遵循以下約定(順序從上至下):?static靜態(tài)方法?constructor?componentWillMount?componentDidMount?componentWillReceiveProps?shouldComponentUpdate?componentWillUpdate?componentDidUpdate?componentWillUnmount?事件處理,如handleClick?render以上規(guī)范約定只是官方建議,開發(fā)者在具體使用過程中可根據(jù)公司團隊或社區(qū)提供的規(guī)范來制定約束,由于內(nèi)容較多且屬于基本知識,因此這里只進行簡單介紹。如果想查看學(xué)習(xí)書寫規(guī)范的相關(guān)內(nèi)容,可參閱Taro官方文檔中關(guān)于書寫規(guī)范部分的內(nèi)容。1.5本章小結(jié)本章介紹了Taro的誕生背景、基本理念及主要特性,同時介紹了使用Taro進行開發(fā)前需要掌握的ES6常用的語法知識、Taro腳手架及規(guī)范約定。相信大家已經(jīng)對使用Taro開發(fā)跨端應(yīng)用有了基本認(rèn)識。從第2章開始,我們正式進入Taro開發(fā)基礎(chǔ)與最佳實踐的講解。第2章Taro基礎(chǔ)本章內(nèi)容圍繞Taro基礎(chǔ)知識展開,主要包括以下內(nèi)容:·JSX·組件化·組件生命周期·事件處理·路由功能·實戰(zhàn)案例:受控與非受控Input組件開發(fā)學(xué)習(xí)完本章內(nèi)容,你將基本掌握Taro的基礎(chǔ)核心知識點。實戰(zhàn)案例引導(dǎo)大家掌握組件狀態(tài)設(shè)計與用戶交互實現(xiàn)方法,從而深刻理解組件狀態(tài)的設(shè)計思想。2.1JSX2.1.1JSX簡介JSX是JavaScriptXML的縮寫,是一種用來描述UI的JavaScript語法糖(SyntacticSugar),Taro支持使用該語法來描述組件的UI表現(xiàn)。初學(xué)JSX,你可能會抱怨該語法的零散與隨意,無法理解在JavaScript代碼中直接書寫HTML代碼。如果你此前使用原生JavaScript或jQuery開發(fā)過大型應(yīng)用,則你一定會抱怨代碼耦合度過高、代碼可維護性差、團隊協(xié)同效率低,而正確使用JSX能很好地解決這些問題。初學(xué)時,你所謂的這些缺點正是它的優(yōu)點,寫法隨意,可讀性更好,更有利于組件封裝與復(fù)用,特別是結(jié)合Hooks使用,可以輕松做到狀態(tài)與視圖解耦合,從而使組件復(fù)用“更上一層樓”。2.1.2JSX語法1.基礎(chǔ)語法JSX通俗理解就是支持在JavaScript代碼中書寫HTML代碼,將JavaScript交互操作與HTML界面定義完美結(jié)合。我們來看使用JSX的一段簡單的代碼:通過以上代碼,我們驚奇地發(fā)現(xiàn),可以將類似HTML代碼片段賦值給一個變量,這種語法就是JSX。注:此處列舉的View是Taro提供的視圖組件,暫且可以將該組件理解為HTML中的div元素。關(guān)于組件的具體內(nèi)容請查看下節(jié)內(nèi)容。2.值渲染與計算既然是JavaScript與HTML的完美結(jié)合,也就是說,我們還可以在類似HTML代碼片段中使用JavaScript變量或執(zhí)行運算等,在HTML中使用JavaScript變量的示例如下:在HTML中執(zhí)行運算:通過以上兩個實例不難發(fā)現(xiàn),在類似HTML代碼片段中使用JavaScript,只需使用{}操作符即可。可以理解為{}中的內(nèi)容是需要交給JavaScript去計算并輸出最終結(jié)果的。3.屬性我們在編寫HTML代碼時,經(jīng)常會在標(biāo)簽中定義很多屬性,例如:·class,指定類名。·style,定義標(biāo)簽樣式?!ぁ贘SX語法中同樣可以定義屬性,但值得一提的是,class等眾多DOM屬性在JavaScript中是關(guān)鍵字或保留字,所以不能使用。例如,在書寫JSX時需要用className代替class,因為class在JavaScript中為關(guān)鍵字:4.條件渲染有時組件UI需要根據(jù)特定條件渲染特定內(nèi)容,例如定義了一個變量flag,當(dāng)變量為true時,頁面顯示“真”;當(dāng)變量為false時,頁面顯示“假”:5.列表渲染使用諸如數(shù)組結(jié)構(gòu)數(shù)據(jù)時,需要遍歷數(shù)據(jù)計算的最終UI結(jié)果。例如定義了一個數(shù)組變量fruits,數(shù)組中包含apple、peach、pear,遍歷該數(shù)組并返回結(jié)果:注:列表渲染一定要在生成的每一項中都添加唯一的key。2.2組件化長期以來,前端開發(fā)者都在探索如何更好地管理項目模塊,都在思考如何設(shè)計各模塊中類似的UI及邏輯以達到高效復(fù)用的目的。早期我們通過定義通用代碼文件,在項目中通過script標(biāo)簽引入方式完成復(fù)用,這種方式確實能在一定程度上實現(xiàn)通用代碼復(fù)用、對應(yīng)模塊版本管理等需求,但在大型項目中,這種方式會顯得很脆弱,模塊之間的依賴管理能力欠缺。后來,有了Bower、Grunt、Gulp等,解決了模塊文件或依賴間的控制問題。再后來,有了Webpack,有了各種模塊化規(guī)范,如AMD、CMD、Commonjs、ESmodule等,前端開發(fā)才進入一個新的世紀(jì)。一路進化,最終組件化、MVC、面向?qū)ο缶幊獭⒑瘮?shù)式編程等思想才得以迸發(fā)。2.2.1初識組件首先來看一個例子,下圖是京東商城首頁,我們站在開發(fā)者的角度來分析一下這個網(wǎng)頁的頁面結(jié)構(gòu)。在使用Taro開發(fā)這個頁面時,首先考慮將頁面內(nèi)容拆分為圖中標(biāo)注的6個模塊,設(shè)計好模塊間的數(shù)據(jù)與UI交互之后,便可以單獨開發(fā)每個模塊,最終組合各個模塊,完成開發(fā)。這里拆解的6個部分,正是6個獨立組件。2.2.2組件定義Taro中的組件分為兩種,一種是基于類創(chuàng)建的組件,被稱為類組件;一種是基于函數(shù)創(chuàng)建的組件,被稱為函數(shù)組件。1.類組件定義類組件是一件很容易的事情,你只需要定義一個類,這個類繼承自Taro.Component,且在組件中定義render方法并返回值即可,代碼示例如下:當(dāng)然,還有為了做優(yōu)化提供的另一種類組件,關(guān)于該組件的原理與用法,我們將在實戰(zhàn)優(yōu)化部分進行詳細介紹,代碼示例如下:2.函數(shù)組件函數(shù)組件相較于類組件,定義更便捷,使用更靈活,尤其搭配Hooks使用能夠在某些場景下替代類組件。函數(shù)組件的定義如下:或者使用箭頭函數(shù),寫法如下:注:在組件中,無論是否使用Taro這個對象,都應(yīng)該將@tarojs/taro包引入。無論組件返回值多么簡單,都盡量使用@tarojs/components提供的組件包裹,而不應(yīng)該直接返回數(shù)字或字符串等。定義好組件后,最終需要將最上層組件也就是根組件掛載到DOM節(jié)點上:為了方便講解,后續(xù)章節(jié)將統(tǒng)一使用類組件,當(dāng)然我們也會在Hooks章節(jié)詳細介紹函數(shù)組件的知識。2.2.3props很多時候,組件中使用的某些數(shù)據(jù)可能需要外部提供,就像我們使用HTML中的圖片標(biāo)簽時,需要設(shè)置src屬性才能顯示對應(yīng)圖片。假如現(xiàn)在定義了一個名叫Timg的類似圖片img的組件,組件內(nèi)部應(yīng)該怎樣獲取外部傳入的屬性數(shù)據(jù)并使用呢?答案是使用props,代碼示例如下:效果如下圖所示。通過props,可以將數(shù)據(jù)傳遞給組件,組件內(nèi)部通過ps獲取對應(yīng)的屬性數(shù)據(jù),渲染即可。有時,某些屬性數(shù)據(jù)并不一定是外部必須傳入的,因此我們在定義組件時,可以設(shè)置默認(rèn)屬性數(shù)據(jù),如上例:若在使用Timg組件時不傳入src屬性,則Timg組件會使用我們通過defaultProps設(shè)置的src屬性的默認(rèn)數(shù)據(jù)渲染頁面。反之,Timg組件會使用外部傳入的src屬性數(shù)據(jù)進行渲染。2.2.4state組件中還有一類數(shù)據(jù),它具備以下幾個特征:·數(shù)據(jù)私有,僅供組件內(nèi)部使用?!?shù)據(jù)需要根據(jù)某些操作發(fā)生更改,并觸發(fā)視圖更新。這些特征正是組件狀態(tài)state期望具備的,滿足這些特征的數(shù)據(jù)一般都要考慮放入組件狀態(tài)state中。我們現(xiàn)在想設(shè)計一個組件,組件中有一個狀態(tài)count,該值每過一秒增加1,并在增加后顯示在頁面中。代碼設(shè)計如下:通過這個示例,我們可以總結(jié)出state的用法:·類組件中有一個名叫state的預(yù)定義屬性,該屬性為對象,對象中記錄了關(guān)于該組件的所有狀態(tài)。如上例中,狀態(tài)count的初始值為1?!ぴ谛枰倪@個狀態(tài)時,調(diào)用組件的setState方法,這個方法繼承自Taro.Component?!ぴ贘SX中,通過this.state獲取對應(yīng)狀態(tài)值并使用。注:任何時候都不要通過賦值的形式直接修改state,如上例中,this.state.count=this.state.count+1這種賦值方式是錯誤的,正確的操作應(yīng)該是用this.setState更新指定狀態(tài)。2.2.5樣式看了以上與組件相關(guān)的例子,對于組件,你是否有種似曾相識的感覺?其實從某種角度來看,組件類似HTML中的標(biāo)簽,這樣類比后,關(guān)于組件的很多問題都能迎刃而解。組件中樣式的使用方法和HTML中一致,也分為兩種:內(nèi)聯(lián)樣式和外部樣式。1.內(nèi)聯(lián)樣式組件的內(nèi)聯(lián)樣式通過style屬性指定。與HTML標(biāo)簽的style屬性不同的是,組件的style屬性接收一個對象:使用內(nèi)聯(lián)樣式需要注意以下幾點:·如果不指定尺寸單位,則會默認(rèn)解析為px,如前面代碼中的width:100,會被解析為width:'100px'?!傩悦臑轳劮迨矫?,如background-color改為backgroundColor。2.外部樣式外部樣式可以使用CSS、Less、Sass等文件定義樣式,然后在對應(yīng)的模塊文件中引入。我們以Less為例:注:我們前面就有提到,因為class為JavaScript關(guān)鍵字,不能出現(xiàn)在JSX中,所以需要使用className替代class。2.3組件生命周期組件從創(chuàng)建到銷毀所經(jīng)歷的整個過程是組件的一生——生命周期。人類從出生到死亡會經(jīng)歷很多人生階段,Taro也為組件劃分了不同階段,方便開發(fā)者在組件的不同階段執(zhí)行不同操作。一般而言,組件生命周期大致分為3個階段:掛載、更新、卸載。與生命周期相關(guān)的方法如下:·static·constructor·componentWillMount·componentDidMount·componentWillReceiveProps·shouldComponentUpdate·componentWillUpdate·componentDidUpdate·componentWillUnmount·render2.3.1組件掛載初次渲染時,需要將組件掛載至對應(yīng)的DOM節(jié)點上,這個階段主要經(jīng)歷了組件實例化、組件將要掛載、組件渲染、組件掛載完畢,對應(yīng)的生命周期方法如下表所示。2.3.2組件更新組件被掛載到DOM以后,組件的props或state發(fā)生更改時會引起組件的更新,通常props變化是因外部變化引起的,state變化是因組件內(nèi)部調(diào)用了setState引起的。這個階段主要經(jīng)歷了組件接收props、組件是否需要更新、組件將要更新、組件渲染、組件更新完畢。對應(yīng)的生命周期方法如下表所示。續(xù)表2.3.3組件卸載這個階段只有一個生命周期方法——componentWillUnmout,卻也是很多人會選擇忽略的一個方法。有時組件被卸載后,組件相關(guān)的內(nèi)容并沒有被清除“干凈”,例如組件中定義的定時器,需要在組件卸載時被清除。在2.2節(jié)關(guān)于組件狀態(tài)的講解中,定義了一個隨時間變化的數(shù)字顯示組件,定時器在組件掛載階段被定義,而組件卸載時并沒有清除這個定時器,我們對這部分代碼進行優(yōu)化:對于初學(xué)者,類組件的生命周期概念晦澀難懂,甚至?xí)霈F(xiàn)錯用、濫用的情況。慶幸的是,函數(shù)組件不存在上面列舉的煩瑣生命周期方法,函數(shù)組件的生命周期可使用Hooks實現(xiàn)。2.4事件處理1.基本使用Taro元素的事件處理和DOM元素的很相似。但是有一點語法上的不同,Taro的事件綁定屬性均以on開頭且為駝峰式命名,事件屬性的值為函數(shù)。下面做一個簡單對比。HTML為元素綁定事件的寫法,示例如下:Taro為組件綁定事件的寫法,示例如下:在Taro中,事件處理函數(shù)的參數(shù)中,同樣可以獲取事件對象,通過事件對象可以進行事件操作,如阻止事件冒泡,代碼示例如下:2.為事件處理函數(shù)傳參假如在一個列表中,列表的每一項都有一個“刪除”按鈕,單擊“刪除”按鈕刪除對應(yīng)的數(shù)據(jù):本例使用函數(shù)的bind方法解決this指向問題,當(dāng)然我們還可以使用箭頭函數(shù):或者使用函數(shù)柯里化思想:上例中,單擊View組件會調(diào)用this.handleClick(current),該函數(shù)調(diào)用后會返回一個新的函數(shù),在這個函數(shù)中可以訪問current值,同時能保證this指向的是當(dāng)前Title組件。3.自定義事件有時存在這樣的需求,期望組件內(nèi)部的狀態(tài)變化或操作能夠傳達給上層,這種需求通常被稱為父子組件之間的通信,父組件期望子組件某個事件觸發(fā)時,父組件執(zhí)行某些特定操作。需要注意的是,自定義事件的屬性名一定要以on開頭,并采用駝峰式命名法,示例如下:2.5路由功能路由的職責(zé)是通過給定路徑,匹配與之對應(yīng)的模塊視圖。在Taro中,路由的相關(guān)定義與微信小程序保持一致,路由功能是默認(rèn)提供的,不需要開發(fā)者進行額外的路由配置。1.基本使用使用路由功能前,我們需要在入口文件的config配置中指定好pages,然后就可以在代碼中通過Taro提供的API來跳轉(zhuǎn)到目的頁面了,配置示例如下:這樣在Index頁面就可以使用Taro提供的API進行路由跳轉(zhuǎn)了,示例如下:2.路由攜帶參數(shù)我們可以通過在所有跳轉(zhuǎn)的URL后面添加查詢字符串參數(shù),從而將參數(shù)攜帶至跳轉(zhuǎn)后的頁面,例如:跳轉(zhuǎn)至目標(biāo)頁面后,我們通過TaroComponent對象上已經(jīng)定義的$router獲取對應(yīng)的參數(shù),示例如下:Taro提供的與路由操作相關(guān)的方法如下表所示。續(xù)表2.6實戰(zhàn)案例:受控與非受控Input組件表單處理是項目中比較常見的功能,表單操作看似比較簡單,其實大有學(xué)問。本節(jié)以Input組件為例,簡單介紹狀態(tài)管理、表單數(shù)據(jù)存儲及事件處理之間的關(guān)聯(lián)設(shè)計。開始之前,我們先思考以下兩種場景:(1)Input框中的值在更改后期望被記錄,然后在提交時拿出記錄的值并傳輸給后端。(2)操作過程中不額外存儲Input框的值,而是在提交時直接獲取Input框的值并傳輸給后端。場景一為什么需要記錄輸入框的值呢?因為有其他地方嘗試修改Input框的值,還不如頁面中有表單的一鍵清空操作;場景二是相對于場景一較為簡單的表單操作,事先我們知道Input框中的值不會在其他地方引起更改,所以我們無須存儲Input框中的值。場景一實現(xiàn)的Input組件是受控表單,場景二實現(xiàn)的是非受控表單。下面來看代碼示例。1.受控Input組件上例是比較經(jīng)典的受控表單處理問題,重點知識通過代碼注釋標(biāo)注。主要思路是:當(dāng)組件初始化時,設(shè)置Input框的初始值為''。在Input框中鍵入數(shù)據(jù)后,失去焦點,則通過事件對象獲取值,并將該數(shù)據(jù)設(shè)置到狀態(tài)中。當(dāng)提交事件被觸發(fā)時,從狀態(tài)中獲取Input框的值并傳輸給后臺,完成表單提交操作。2.非受控Input組件上例是比較經(jīng)典的非受控表單處理問題,重點知識通過代碼注釋標(biāo)注。主要思路是:當(dāng)組件初始化時,創(chuàng)建用于引用Input組件實例的對象,該對象可以使用Input組件內(nèi)部的方法或獲取Input內(nèi)部的值(Value)。當(dāng)提交事件被觸發(fā)時,通過inpRef獲取Input組件實例中的值并傳輸給后臺,完成表單提交操作。2.7本章小結(jié)本章介紹了JSX語法基礎(chǔ),包括組件化開發(fā)基本思想、組件生命周期、組件中事件的處理,以及如何綁定事件、如何解決this指向問題等。了解了單個頁面開發(fā)以后,我們可以嘗試將多個頁面有機組合,這時就需要使用路由功能了。路由系統(tǒng)將各個模塊通過路徑和路徑參數(shù)編織成網(wǎng),路由操作允許你在網(wǎng)的節(jié)點之間穿梭。最后以表單控件串聯(lián)起了本章學(xué)習(xí)的重要內(nèi)容,舉一反三。下一章我們將更深入地學(xué)習(xí)組件開發(fā)與組件設(shè)計思想。第3章Taro進階本章將深入探討Taro組件化開發(fā)內(nèi)容,組件化帶給我們友好開發(fā)體驗的同時,帶來了很多問題,諸如:·組件設(shè)計原則與分類問題?!ど顚咏M件狀態(tài)傳遞問題?!そM件通信問題。·引用問題。本章內(nèi)容將圍繞以上問題展開,學(xué)習(xí)完本章你會對組件設(shè)計有更深入的認(rèn)識,為以后編寫出更易讀、可維護性更高的應(yīng)用奠定基礎(chǔ)。3.1組件設(shè)計你也許聽過這樣一句話:總體大于部分之和。以往我們對這句話都是不假思索地給予肯定,但在我們要講的組件設(shè)計這個場景下,總體帶來的收益并不一定大于部分之和,這里的收益包括開發(fā)效率、代碼可讀性、代碼可維護性等。初學(xué)者經(jīng)常會犯一個致命的錯誤——過早設(shè)計與優(yōu)化。曾有剛?cè)肼毠镜膶嵙?xí)生問筆者,組件到底應(yīng)該怎么設(shè)計,什么時候應(yīng)該進一步拆分組件,拆分組件的時候應(yīng)該如何考慮狀態(tài)問題。其實針對這些問題并沒有絕對的答案,但是有幾個基本原則可以在組件設(shè)計時借鑒。1.單一職責(zé)相信學(xué)習(xí)過面向?qū)ο缶幊痰淖x者都知道面向?qū)ο缶幊痰脑O(shè)計原則,其中就有單一職責(zé),定義為:一個類發(fā)生變化的原因只應(yīng)該有一個。將這個定義放在函數(shù)式編程中就可以描述為:一個函數(shù)只應(yīng)該有一個自變量(參數(shù)),應(yīng)變量只隨這一個自變量變化。在Taro中,組件即模塊。單一職責(zé)要求在設(shè)計組件時做到“單一”,這一點我們大多時候都能滿足,而其中的難點在于組件單一的粒度:粒度太大不好復(fù)用,粒度太小會導(dǎo)致定義大量模塊,從而讓項目變得難以管理。所以需要把握好單一的度。遵循單一職責(zé)所設(shè)計出的組件具有以下特點:·組件復(fù)雜度降低?!づc其他組件的耦合度降低。·可復(fù)用性提高。2.高內(nèi)聚,低耦合高內(nèi)聚要求一個組件有一個明確的組件邊界,組件將包容相關(guān)緊密聯(lián)系的內(nèi)容,實現(xiàn)“專一”功能。低耦合要求與其他組件的關(guān)聯(lián)性最小。當(dāng)然本條原則需要依賴第一條,只有考慮單一職責(zé)設(shè)計出的組件才能預(yù)知組件邊界,實現(xiàn)高內(nèi)聚,降低與其他組件的關(guān)聯(lián)性,實現(xiàn)低耦合。3.性能與優(yōu)化以上兩點主要從上層設(shè)計層面分析了組件設(shè)計需要遵循的基本原則,在完成以上兩步設(shè)計后,還需要考量以下幾點:·基于性能選擇合適組件:無狀態(tài)組件>有狀態(tài)組件>class組件?!ぷ钚』痯rops?!と绻皇且呀?jīng)確定的組件完整形態(tài),請不要過早優(yōu)化。3.2組件通信上一節(jié)我們了解了組件的設(shè)計思想,組件在被設(shè)計出來以后不是孤立的,也需要“交往”。例如下面的組件結(jié)構(gòu):MyContent與MySide的關(guān)系被稱為父子組件關(guān)系,MySide與MyList的關(guān)系被稱為兄弟組件關(guān)系。有時可能在MySide中的操作需要通知MyList,或者MySide中的操作需要通知MyContent,這一需求背后正是父子組件或兄弟組件之間的通信。3.2.1父子組件通信一般而言,父子組件之間的通信通過事件完成,即在父組件定義事件處理函數(shù),將這個函數(shù)作為props傳遞給子組件,就能實現(xiàn)指定子組件的操作通知到父組件。示例如下:上例說明了子組件操作觸發(fā)父組件的邏輯處理。那么父組件的操作觸發(fā)子組件的更新呢?便是通過props了,父組件數(shù)據(jù)更新后,通過props告知子組件,示例如下:這種方式其實是將MySide中的count狀態(tài)抽離出來存放到父組件,使得父組件或者父組件內(nèi)的其他組件更改這個值變得容易。如果父組件希望觸發(fā)子組件內(nèi)的操作,則可以結(jié)合引用Ref獲取子組件實例,然后通過引用使用子組件中的值或方法,具體使用方法我們將在3.4節(jié)介紹。3.2.2兄弟組件通信兄弟組件狀態(tài)同步只能通過父組件實現(xiàn),即將兄弟組件需要共用的狀態(tài)提取到父組件中,進而在兄弟組件上使用自定義事件的方式監(jiān)聽組件內(nèi)部的操作。如果值發(fā)生更改,則需要通知其兄弟組件,代碼實現(xiàn)示例如下:回想一下,在討論組件設(shè)計需要遵循的原則時,我們說組件的邊界要清晰,但是我們現(xiàn)在發(fā)現(xiàn)上例中MySide組件和MyList組件共同依賴了count這一狀態(tài)。這時我們需要思索,這個問題出現(xiàn)的原因是什么,是組件設(shè)計粒度不合理?還是組件之間確實需要共用這個狀態(tài)?如果是前者,則需要重新考慮一下組件的設(shè)計;如果是后者,則可以用本例所示的解決方案去解決這一問題。3.2.3更復(fù)雜的組件通信大多數(shù)情況下,以上列舉的兩種方案可以很好地解決組件之間的狀態(tài)同步問題??赏€有更復(fù)雜的場景、更復(fù)雜的狀態(tài)同步問題亟待解決。例如,更深層級的狀態(tài)傳遞與通信,且該狀態(tài)只被最內(nèi)層組件消費,以及狀態(tài)合并問題等。這里我們來看深層狀態(tài)傳遞問題。首先我們可以想到通過props逐層傳遞,例如:Two組件很顯然只是中介,count屬性傳遞給了它卻沒有被使用,只是透傳給了One組件。是否可以不經(jīng)過這樣層層傳遞,而直接由Three組件創(chuàng)建狀態(tài),One組件使用這個狀態(tài)呢?這就需要使用Taro提供的context實現(xiàn)。代碼示例如下:這樣一來,count這一狀態(tài)就只是Three組件創(chuàng)造與更新、One組件消費了。這樣props更簡捷,沒有造成污染。如果以上方案還是無法解決應(yīng)用中的狀態(tài)管理問題,就可能需要使用全局狀態(tài)管理了,關(guān)于復(fù)雜組件的狀態(tài)管理我們將在下一章詳細探討。3.3服務(wù)端通信應(yīng)用中大多數(shù)據(jù)來自后端,掌握前后端數(shù)據(jù)請求至關(guān)重要。Taro提供了統(tǒng)一接口,用于網(wǎng)絡(luò)HTTP/HTTPS請求,該接口為Taro.request(options)。3.3.1Taro.request學(xué)習(xí)該接口之前,先整體介紹一下request常用的options參數(shù),如下表所示。請求得到數(shù)據(jù)以后,Taro會將返回的數(shù)據(jù)及狀態(tài)等內(nèi)容進行封裝,封裝后得到的這個對象我們暫且稱為ResultObject,該對象主要包含四個屬性,如下表所示。Taro在大多數(shù)方面都考慮到了開發(fā)者的學(xué)習(xí)成本,我們從請求API也能夠看出,Taro.request的相關(guān)設(shè)計借鑒了fetch,你只要使用過fetch,就能很快上手Taro.request。假如現(xiàn)在需要使用Taro在組件中向后端發(fā)送一條登錄請求,我們會如下所示進行代碼編寫:相信你能很輕松地理解以上代碼,但是我們發(fā)現(xiàn)以上請求的處理是放在回調(diào)函數(shù)中的,而回調(diào)函數(shù)的解耦合能力或者可讀性與可維護性較低,在Taro項目中建議使用Promise替代。改寫示例如下:或者:3.3.2請求終止在某些特殊情況下,可能在較短時間內(nèi)發(fā)出多個相同的請求,如此一來最終我們得到這個請求的響應(yīng)也可能會有多個,這時就會面臨一個問題,如果只想保留最后發(fā)起的那一次請求所得到的數(shù)據(jù),該如何實現(xiàn)呢?這個問題是典型的時序控制問題,比較暴力的解決方案是每次發(fā)起請求前都將之前所發(fā)起的請求終止。在調(diào)用了Taro.request方法后會返回一個請求對象實例,該實例允許終止該次請求。示例如下:有了這個API,上述需求就能輕易實現(xiàn):上例代碼的主要思路是:在組件創(chuàng)建時創(chuàng)建一個引用對象,當(dāng)“登錄”按鈕被單擊時,會先判斷此時引用是否已經(jīng)賦值為Taro請求對象,若該引用指向的Taro請求對象存在,則本次請求終止,然后創(chuàng)建一個最新的請求對象并賦值給引用,以此保證組件獲取的數(shù)據(jù)來自最后一次發(fā)起的請求。注:上例使用的引用會在下一節(jié)展開介紹。3.3.3請求攔截器攔截器能夠在請求發(fā)出前或發(fā)出后將請求攔截并對其options進行一些額外處理,攔截器可以讓你更優(yōu)雅地去改變已有程序的表現(xiàn)。攔截器的處理過程類似洋蔥,所以我們常稱攔截器處理為洋蔥模型,如下圖所示。在請求發(fā)起之前,可使用Taro.addInterceptor為請求添加攔截器。Taro也有內(nèi)置攔截器供使用。1.內(nèi)置攔截器Taro提供了兩個內(nèi)置攔截器,分別是logInterceptor和timeoutInterceptor。顧名思義,前者是用于請求日志輸出的攔截器,后者是用于設(shè)置請求超時時間的攔截器。使用方法如下:添加logInterceptor攔截器以后,后面的每次請求都會輸出請求的相關(guān)信息,如請求路徑、參數(shù)、方法等。添加timeoutInterceptor攔截器以后,后面的請求如果超出預(yù)期時間依然沒有獲得返回結(jié)果,則這次請求將會被超時處理。2.自定義攔截器攔截器其實是一個特殊方法,該方法的參數(shù)攜帶了請求options,并且該方法體中的內(nèi)容處理完后必須返回一個Promise以進行后續(xù)操作。假如我們現(xiàn)在想自定義一個日志攔截器,實現(xiàn)如下:當(dāng)請求發(fā)起時,會打印請求方法、請求路徑及請求參數(shù);當(dāng)請求響應(yīng)到來時,會打印路徑及響應(yīng)參數(shù)。以上兩處console.log是業(yè)務(wù)中需要自定義攔截器處理的邏輯,第一位置可用于處理請求內(nèi)容,第二位置可用于處理響應(yīng)內(nèi)容。使用攔截器在拓展處理請求響應(yīng)內(nèi)容的同時不會造成代碼侵入,這種思想是經(jīng)典的面向切面編程(AspectOrientedProgramming,AOP)思想。如果你對該思想感興趣,可以查閱相關(guān)資料進一步學(xué)習(xí)。3.4使用Ref對于Ref,你可能已經(jīng)不陌生了,前面有兩處提到了Ref。第一處是第2章講解非受控表單時,獲取Input組件對象進而獲取該組件的Value;第二處是講解請求時序控制時,確保在較短時間內(nèi)同一個請求發(fā)出多次,只須將最后一次請求獲得的數(shù)據(jù)渲染到頁面中。本節(jié)將全面梳理Taro中Ref的使用。1.引用組件在Web開發(fā)時,我們可以使用document.getElementById等方法獲取指定節(jié)點元素,而在Taro中無法使用這些DOM操作方法,因為Taro是數(shù)據(jù)驅(qū)動框架。幸運的是,可以使用Ref獲取指定節(jié)點,例如獲取一個表單元素的值,示例如下:在組件創(chuàng)建時,創(chuàng)建了一個用于指代Input組件的引用。在組件掛載時,該引用會指向Input實例,在后續(xù)的操作中就能通過該引用獲取Input組件的內(nèi)容了。還記得我們在3.2節(jié)留下了一個伏筆,在父組件中如何使用子組件中的屬性或方法。這也是Ref的另一個用武之地,你可以將Ref運用在自定義組件上來獲取組件實例,示例如下:其實,如果你經(jīng)常在父組件中通過子組件引用來使用子組件中的屬性或方法,那么也許你需要思考片刻,是不是因為你的組件設(shè)計不合理迫使你這樣做?因為引用其實也算打破了組件邊界,對組件外部暴露的內(nèi)容越多,說明組件封裝越需要優(yōu)化。2.請求時序控制時序控制需要確保在較短時間內(nèi)同一個請求發(fā)出多次,只須將最后一次請求獲得的數(shù)據(jù)渲染到頁面中。使用方法在上一節(jié)已做分析,此處不再贅述。對于Ref,我們可以將其理解為旁觀者,它以慵懶的姿態(tài)記錄你所給定的值,并且不會隨組件的更新而發(fā)生變化,Ref的變化只來自初始化、掛載及后續(xù)手動賦值。3.5本章小結(jié)本章介紹了組件設(shè)計的基本原則。首先介紹了組件關(guān)系,組件之間的通信即狀態(tài)同步問題。然后介紹了組件與服務(wù)端數(shù)據(jù)交互和通信使用的API,同時介紹了如何使用攔截器在請求發(fā)出前或響應(yīng)到來后做一些特殊處理。最后介紹了Ref在開發(fā)過程中的使用方法。通過前面3章的學(xué)習(xí),我們已經(jīng)較深入地掌握了Taro開發(fā)基礎(chǔ)與組件設(shè)計等內(nèi)容。有一個亟待解決的問題,組件設(shè)計時遇到復(fù)雜狀態(tài)應(yīng)該如何處理,這時就可能需要將部分狀態(tài)進行集中管理,下一章我們將圍繞這個問題給出不同的可選方案。第4章集中狀態(tài)管理大多數(shù)項目中的組件功能通過上一章所講的架構(gòu)就能實現(xiàn),但也存在更多復(fù)雜的場景。例如模塊之間需要共用某些狀態(tài),某模塊中需要更改另一模塊的數(shù)據(jù)或狀態(tài),這時,無論通過提升狀態(tài)還是拆分組件,似乎都只會讓項目代碼的可讀性下降且不易維護。在這種場景下,也許需要其他狀態(tài)管理方案。4.1Redux在React中,比較流行的狀態(tài)管理方案中就有Redux。其實Redux本身和React或者Taro沒有直接聯(lián)系。換言之,只要是JavaScript應(yīng)用,都可以使用Redux作為數(shù)據(jù)管理工具。只是在Taro中,為了簡化Redux的使用,定義了與react-reduxAPI幾乎一致的包——@tarojs/redux。4.1.1Redux設(shè)計理念單頁應(yīng)用日趨復(fù)雜,應(yīng)用中的數(shù)據(jù)越來越難以管理。假設(shè)一個應(yīng)用中的狀態(tài)或者數(shù)據(jù)使用一個簡單對象來描述,可能會像這樣:這個對象定義了一個計劃應(yīng)用中的待辦事項列表。通常列表項的操作可能不止在一個模塊中。當(dāng)一個狀態(tài)需要在多個模塊中更新時,直接修改對象的值是非常不明智的,有沒有更好的方案呢?有!單向數(shù)據(jù)流。關(guān)于單向數(shù)據(jù)流的概念我們不展開介紹,因為概念本身就是抽象的,我們暫且從實際問題出發(fā)。我們繼續(xù)思考多個模塊修改一個狀態(tài)的問題,既然不能直接修改對象的值,那么我們不妨先描述一下需要對這個對象進行的操作,例如添加待辦列表項、改變待辦列表項的狀態(tài)。在定義了這些操作以后,還要考慮在相同操作情況下處理的實際參數(shù)可能有所差異,因此每次操作都可以攜帶本次操作的參數(shù)(payload)。例如:這樣就定義了兩個操作,對應(yīng)添加和更改狀態(tài)。添加操作攜帶了text參數(shù)用于填充添加項的內(nèi)容,更改狀態(tài)操作攜帶了index參數(shù)用于指定需要更改項的索引。這樣就能清晰地知道更新后應(yīng)用中到底發(fā)生了什么。接下來應(yīng)用狀態(tài)的更新交給reducer。reducer用于處理不同操作,如ADD_TODO,該操作就是在原有列表的基礎(chǔ)上新增一項,如果是數(shù)組,可以如下:如果是TOGGLE_TODO,則需要更新原有列表中的某項。這樣我們就可以將上述兩種操作定義在一個處理函數(shù)中,示例如下:需要注意的是,每個處理函數(shù)都應(yīng)該是純函數(shù)。最終只需要通過action與reducer創(chuàng)建store即可使用,使用方法如下:4.1.2在Taro中使用Redux首先安裝Redux、@tarojs/redux和@tarojs/redux-h5,以及一些需要用的Redux中間件,示例如下:然后可以在項目的src目錄下新增一個store目錄,在該目錄下創(chuàng)建index.js文件來配置store,同時可以選擇常用的Redux中間件并配置到項目中,例如使用redux-thunk和redux-logger中間件分別處理異步操作和記錄Redux操作日志,示例如下:接下來在項目入口文件app.js中使用@tarojs/redux中提供的Provider組件將已經(jīng)定義的store提供給項目組件使用,代碼示例如下:這樣就可以開始使用了。如Redux推薦的那樣,可以增加如下目錄:·constants目錄,用來放置所有的actiontype常量?!ctions目錄,用來放置所有的actions?!educers目錄,用來放置所有的reducers。4.1.3Redux案例我們使用Redux來開發(fā)一個簡單的加、減計數(shù)器功能。1.新增actiontype我們需要通過不同的action名稱枚舉出不同的action操作,如計數(shù)操作要設(shè)計增加和減少操作,所以需要定義兩個actiontype,分別對應(yīng)加和減,示例如下:2.新增reducer處理當(dāng)不同的操作發(fā)起請求時,我們需要對不同的請求作出響應(yīng),并返回最新狀態(tài)。前面我們介紹了action存在加和減兩個類型,那么reducer中需要根據(jù)這兩個不同的類型返回不同的狀態(tài)。對于增加操作,首先獲取已存儲狀態(tài)中的num值,然后將該值加1。為了不影響狀態(tài)中的其他值,我們通過解構(gòu)賦值的方式將已存儲狀態(tài)解構(gòu)賦值到新的對象中,然后指定num值以覆蓋更新前的num值,最終返回這個對象,從而生成新的狀態(tài),代碼示例如下:通過redux提供的combineReducers方法,可以將定義的多個reducer合并,示例如下:3.新增action處理定義action函數(shù)的目的是進一步約束可發(fā)起狀態(tài)變化的操作場景,本例中num的變化只能是通過ADD或MINUS操作引起的,因此在組件中可以預(yù)先定義好對應(yīng)的處理函數(shù),在需要使用的位置調(diào)用即可,代碼示例如下:通過以上3步,定義了action類型、action處理、reducer處理,接下來就可以在組件中使用了,示例如下:以上connect裝飾器接收參數(shù)mapStateToProps與mapDispatchToProps,分別如下:·mapStateToProps,函數(shù)類型,接收最新的state作為參數(shù),用于將state映射到組件的props?!apDispatchToProps,函數(shù)類型,接收dispatch()方法并返回期望注入展示組件的props中的回調(diào)方法。4.2MobX使用Redux做狀態(tài)管理是一個不錯的選擇,但通過上一節(jié)的介紹,你似乎已經(jīng)發(fā)現(xiàn)Redux是有一定的學(xué)習(xí)成本的。什么是單向數(shù)據(jù)流?為什么需要定義actiontype?為什么需要定義reducer?這些問題在我們初學(xué)時比較難考慮清楚,并且有時希望選擇一個更自由、更簡單易用的狀態(tài)管理工具,也許MobX能夠滿足要求。4.2.1MobX設(shè)計理念MobX的設(shè)計比Redux小巧精簡,它不用定義reducer,也不需要通過純函數(shù)形式生成新的state。使用MobX只需要熟悉以下3個概念:·狀態(tài)state?!づ缮礵erivations?!げ僮鱝ction。MobX支持單向數(shù)據(jù)流,其中,action會更改state,同時會更新所有與該狀態(tài)相關(guān)的視圖,如下圖所示。使用MobX時,狀態(tài)集合可以使用對象來描述,并且只要使用MobX提供的observable方法包裹對象,就能返回一個被檢測的對象。Taro提供了MobX實用工具庫——@tarojs/mobx。4.2.2在Taro中使用MobX安裝相關(guān)依賴,示例如下:我們一般將組件狀態(tài)封裝到一個對象中。如detail模塊,需要存儲公共狀態(tài),這時我們可以創(chuàng)建一個文件,命名為detail-store.js。這個文件默認(rèn)返回detail狀態(tài),示例如下:在本示例中,content、views參數(shù)被指定為MobX的觀測屬性,increateViews被指定為會引起觀測屬性變化的操作,這樣我們就可以在detail組件文件中使用該狀態(tài)了,示例如下:observer是一個高階組件,通過該注解,使得組件跟隨MobXstore的變化而更新。本例中當(dāng)“增加”按鈕被單擊時,頁面的瀏覽數(shù)就能增加。但是這樣的store還是只能在本組件或者子組件中使用,如果期望跨組件都能訪問到這個store,就需要將store從應(yīng)用頂層注入,供所有組件消費。這個操作在src/App.js中被定義,示例如下:這樣在需要使用公共store的組件上通過inject注解,將指定的store綁定到組件props上,即可在組件內(nèi)訪問使用,示例如下:需要注意以下兩件事情?!o論以何種方式使用inject,其后的observer均不能省略?!げ灰趇nject中引用可觀察對象,這將導(dǎo)致屬性改變后的頁面不更新,例如:4.3本章小結(jié)本章介紹了項目中常用的兩種集中狀態(tài)管理方案,不過也許你的項目并不需要。小型項目直接使用組件內(nèi)部state即可實現(xiàn)狀態(tài)管理,或者使用Hooks進行狀態(tài)管理,下一章將展開講解關(guān)于Hooks的知識。大型項目考慮是否需要使用集中狀態(tài)管理,同時集中狀態(tài)管理的方案還有很多。如果你覺得Redux復(fù)雜但還是想使用基于Redux狀態(tài)管理的方案,那么可以選用dva;如果你的狀態(tài)流控制異常復(fù)雜,則可以考慮選用RxJs。Redux和MobX對于狀態(tài)管理的思想值得我們仔細研究學(xué)習(xí)。第5章Hooks前面的章節(jié),我們都是使用class定義組件的。class組件符合面向?qū)ο缶幊趟枷耄瑑?yōu)點很多,但缺點也很多。在Taro中,很多場景下函數(shù)式編程思想優(yōu)于面向?qū)ο缶幊趟枷?。正因如此,Taro引入了Hooks的特性。Hooks允許在函數(shù)式組件中管理狀態(tài)及其他特性。5.1Hooks簡介在此之前,有狀態(tài)組件只能使用class定義,但在某些場景下,class組件會引入一些問題,后來出現(xiàn)了函數(shù)組件。過去函數(shù)組件又被稱為stateless組件,即無狀態(tài)組件。但經(jīng)過嘗試發(fā)現(xiàn),函數(shù)組件在對組件UI與狀態(tài)的分離方面表現(xiàn)出色,由此Hooks應(yīng)運而生。在介紹Hooks之前,我們先來細數(shù)class組件的不足。5.1.1class組件的不足1.組件之間難以復(fù)用狀態(tài)邏輯如果你使用過Taro一段時間,你也許會熟悉一些解決狀態(tài)復(fù)用問題的方案,如renderprops和高階組件。但這類方案需要重新組織你的組件結(jié)構(gòu),使你的代碼難以理解。并且你會發(fā)現(xiàn)由providers、consumers、高階組件、renderprops等其他抽象層組成的組件會形成“嵌套地獄”。因此Taro需要為共享狀態(tài)邏輯提供更好的原生途徑。2.復(fù)雜組件難以理解起初組件很簡單,但是逐漸會被狀態(tài)邏輯和副作用充斥。每個生命周期常常包含一些不相關(guān)的邏輯。例如,組件常在componentDidMount和componentDidUpdate中獲取數(shù)據(jù)。但是,同一個componentDidMount中可能包含很多其他邏輯,如設(shè)置事件監(jiān)聽,而后需在componentWillUnmount中清除事件。相互關(guān)聯(lián)且需要對照修改的代碼被拆分,而完全不相關(guān)的代碼卻在同一個方法中被組合。如此很容易產(chǎn)生Bug,導(dǎo)致邏輯不一致。3.難以理解的面向?qū)ο缶幊趟枷氤a復(fù)用和代碼管理會遇到困難外,面向?qū)ο缶幊趟枷胍彩鞘褂肨aro的一大屏障。你必須理解JavaScript中this的工作方式,不能忘記綁定事件處理器。也許我們很好理解props、state和自頂向下的數(shù)據(jù)流,但對面向?qū)ο缶幊趟枷雲(yún)s一籌莫展。為了解決以上問題,Taro提供了Hooks。Hooks可以使你在非class的情況下使用更多的Taro特性。Hooks充分擁抱函數(shù),同時沒有犧牲Taro的精神原則。Hooks提供了問題的解決方案,無須學(xué)習(xí)復(fù)雜的函數(shù)式或響應(yīng)式編程技術(shù)。Hooks是一系列可以讓你在函數(shù)組件中管理并使用state及生命周期等特性的函數(shù)。需要注意的是,Hooks不能在class組件中使用。5.1.2Hooks概覽我們以兩個最常用的Hooks作為示例,體驗基于Hooks開發(fā)應(yīng)用。這兩個Hooks分別為useState和useEffect。1.useState首先來看一個計數(shù)器案例,需求很簡單。當(dāng)你單擊按鈕時,計數(shù)器的值會增加1,并顯示在頁面中。代碼如下:在這里,useState就是一個Hook(后面我們詳細介紹)。通過在函數(shù)組件里調(diào)用它,為組件添加一些內(nèi)部狀態(tài),Taro會在更新渲染時保留這個狀態(tài)。useState會返回一對值:當(dāng)前狀態(tài)和一個讓你更新它的函數(shù),你可以在事件處理函數(shù)中或其他一些地方調(diào)用這個函數(shù)。該函數(shù)類似class組件中的this.setState。在上面的例子中,計數(shù)器是從零開始的,所以初始state就是0。這里的state可以是你期望的任何類型數(shù)據(jù)。這個初始state參數(shù)只有在第一次渲染組件時被用到。如果組件中有多個狀態(tài)需要管理,則可以調(diào)用多個useState來生成狀態(tài)和該狀態(tài)的更新函數(shù),例如:上例中,我們在一個函數(shù)組件中定義了3個狀態(tài),分別為age、fruit、todos,同時對應(yīng)的更新函數(shù)是setAge、setFruit、setTodos。需要注意這里的命名,推薦將狀態(tài)對應(yīng)的更新函數(shù)命名為“set+狀態(tài)名”的形式。之后,只要在需要的時候調(diào)用狀態(tài)更新函數(shù),視圖就會根據(jù)新的狀態(tài)重新渲染。2.useEffect在了解這個函數(shù)之前,我們先來認(rèn)識一個術(shù)語——副作用。生活中我們常聽說這個詞,例如感冒了,需要喝藥,但喝藥是有副作用的,副作用就是嗜睡。在程序中,一個狀態(tài)改變的時候會引起其他視圖或狀態(tài)的更改,這也被稱為副作用。在計數(shù)器案例中,當(dāng)count狀態(tài)改變時,我們期望更新標(biāo)題,這時就需要處理count狀態(tài)的副作用了,代碼如下:當(dāng)你在組件中使用了useEffect,那么組件在掛載和更新時就會嘗試處理這個副作用。useEffect傳入兩個參數(shù),第一個參數(shù)是副作用的處理函數(shù),第二個參數(shù)是與該副作用關(guān)聯(lián)的狀態(tài)或?qū)傩砸蕾嚁?shù)組,就像上例指明了count,說明本useEffect只在count變化時執(zhí)行副作用處理函數(shù)。這里發(fā)散一下思維,如果我們期望useEffect只在組件掛載時執(zhí)行,則該怎么做呢?可以如下使用:同時useEffect允許返回一個函數(shù),這個函數(shù)用于處理清除操作,類似componentWillUnmout,示例如下:與useState一樣,同一個組件中可以使用多個useEffect,例如:5.1.3Hooks規(guī)則Hooks是特殊的函數(shù)。準(zhǔn)確來說,Hooks的實現(xiàn)使用了函數(shù)閉包思想,因此在使用Hooks過程中,如果出現(xiàn)一些難以理解的問題,則可以猜測是否是閉包引起的問題。在使用Hooks時,需要記住以下幾點規(guī)則:·只能在函數(shù)組件中使用Hooks?!ぶ荒茉诤瘮?shù)塊中使用Hooks。不能在循環(huán)、條件判斷或子函數(shù)中使用Hooks。5.2Hooks基礎(chǔ)通過上節(jié)中的案例,相信你已經(jīng)對Hooks有了一定認(rèn)識,甚至你已迫切想要嘗試用Hooks來進行開發(fā)。Taro提供了很多Hooks,如果這些Hooks無法滿足日常開發(fā)中的需求,也可以根據(jù)規(guī)則自定義Hooks。內(nèi)置Hooks都定義在@tarojs/taro中,所以可以這樣引入對應(yīng)的Hooks:5.2.1useState該方法接收一個參數(shù)用于初始化狀態(tài),返回值為一個數(shù)組,數(shù)組中第一項為狀態(tài),第二項為該狀態(tài)的更新函數(shù)。使用示例如下:組件初次渲染時,count狀態(tài)會被賦值為0,后續(xù)在組件中調(diào)用setCount就可以使count狀態(tài)更新。但有時初始狀態(tài)可能需要經(jīng)過計算惰性初始化,這時可以傳入函數(shù)并返回對應(yīng)值來初始化狀態(tài),例如:假設(shè)在組件中有一個按鈕,當(dāng)單擊按鈕時,將count加1,可以這樣實現(xiàn):或者使用回調(diào)函數(shù)形式實現(xiàn)count值的更新:5.2.2useEffect該方法接收兩個參數(shù),第一個參數(shù)為處理副作用的函數(shù),第二個參數(shù)為引起該副作用執(zhí)行的值數(shù)組。以前在使用函數(shù)組件時,無法在組件中進行DOM操作,因為函數(shù)組件每次更新都會重新執(zhí)行函數(shù)中的邏輯。引入useEffect以后,將DOM、請求等操作放于其中,實現(xiàn)與class組件類似的效果。在函數(shù)組件中,使用useEffect可以實現(xiàn)類似class組件的componentDidMount生命周期函數(shù),示例如下:第二個參數(shù)指定為空數(shù)組時,表示該副作用不依賴任何的值變化,只會在組件完成初次渲染后執(zhí)行一次。使用useEffect同樣可以實現(xiàn)類似class組件的componentWillUnmout生命周期函數(shù),示例如下:顯然,useEffect返回的函數(shù)即可定義該副作用的清除邏輯。使用useEffect還可以實現(xiàn)類似class組件的componentDidUpdate生命周期函數(shù)。值得一提的是,使用useEffect來處理更新優(yōu)于使用componentDidUpdate,因為useEffect在一個組件中可定義多個。也就是說,不同的值變化可以在不同的副作用中進行處理,這樣就解決了class組件的componentDidUpdate函數(shù)中冗余太多不相關(guān)代碼的問題。對比如下:使用class組件使用函數(shù)組件+Hooks5.2.3useReducer通常使用useState和useEffect基本能滿足函數(shù)組件狀態(tài)管理的需求,但也難免會有更加復(fù)雜的場景。我們現(xiàn)在虛擬一個計算器組件,需要實現(xiàn)計算器的加減乘除等操作,顯然這些方法如果都分散定義,會導(dǎo)致狀態(tài)管理混亂。這時我們想到了Redux狀態(tài)管理的思想——單向數(shù)據(jù)流?,F(xiàn)在Hooks也提供了這個功能。useReducer接收三個參數(shù),第一個參數(shù)是處理狀態(tài)更新的reducer,第二個參數(shù)是狀態(tài)初始值,第三個參數(shù)是狀態(tài)初始化函數(shù)。使用示例如下:第一個參數(shù)定義與Redux章節(jié)講解的reducer定義一樣,用于響應(yīng)不同action類型并返回新的狀態(tài)。例如我們現(xiàn)在定義count的加減1操作,示例如下:第二個參數(shù)用于定義初始狀態(tài)值,例如計算器組件在初始化時,會將count初始化為0,那么我們定義的initialArg如下:一般情況下,定義了這兩個參數(shù)后就可以使用useReducer了,在組件中的使用方法如下:從這個例子可以發(fā)現(xiàn),使用useReducer來管理狀態(tài)比使用useState更符合封閉原則。并且如果有時外部傳入的p

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論