摘要:但是如果多實(shí)例組件的含義明顯不具有通用性,特別是用于顯示數(shù)組元素的情況下,使用這種模式會(huì)引發(fā)多余的渲染過(guò)程。假設(shè)我們還有數(shù)組,數(shù)組元素的格式與一樣我們要用相同的元素組件來(lái)同時(shí)顯示和操作這兩個(gè)數(shù)組時(shí),這種數(shù)組渲染模式就不適用了。
這是 Pastate.js 響應(yīng)式 react state 管理框架系列教程的第三章,歡迎關(guān)注,持續(xù)更新。
這一章我們來(lái)看看在 pastate 中如何渲染和處理 state 中的數(shù)組。
渲染數(shù)組首先我們更新一下 state 的結(jié)構(gòu):
const initState = { basicInfo: ..., address: ..., pets: [{ id:"id01", name: "Kitty", age: 2 }] }
我們定義了一個(gè)有對(duì)象元素構(gòu)成的數(shù)組 initState.pets, 且該數(shù)組有一個(gè)初始元素。
接著,我們定義相關(guān)組件來(lái)顯示 pets 的值:
class PetsView extends PureComponent { render() { /** @type {initState["pets"]} */ let state = this.props.state; return () } }My pets:{state.map(pet =>)}
class PetView extends PureComponent { render() { /** @type {initState["pets"][0]} */ let state = this.props.state; return () } }{state.name}: {state.age} years old.
這里定義了兩個(gè)組件,第一個(gè)是 PetsView,用來(lái)顯示 pets 數(shù)組; 第二個(gè)是 PetView,用來(lái)顯示 pet 元素。
接下來(lái)把 PetsView 組件放入 AppView 組件中顯示:
... class AppView extends PureComponent { render() { /** @type {initState} */ let state = this.props.state; return () } } ...
完成!我們成功渲染了一個(gè)數(shù)組對(duì)象,這與用原生 react 渲染數(shù)組的模式一樣,頁(yè)面結(jié)果如下:
修改數(shù)組首先,我們想添加或減少數(shù)組元素,這用 pasate 實(shí)現(xiàn)起來(lái)非常簡(jiǎn)單。受 vue.js 啟發(fā),pastate 對(duì) store.state 的數(shù)組節(jié)點(diǎn)的以下7個(gè) 數(shù)組變異方法 都進(jìn)行了加強(qiáng),你可以直接調(diào)用這些數(shù)組函數(shù),pastate 會(huì)自動(dòng)觸發(fā)視圖的更新。這 7 個(gè)數(shù)組變異方法如下
push()
pop()
shift()
unshift()
splice()
sort()
reverse()
我們來(lái)嘗試使用 push 和 pop 來(lái)更新數(shù)組:
class PetsView extends PureComponent { pushPet(){ state.pets.push({ id: Date.now() + "", name: "Puppy", age: 1 }) } popPet(){ state.pets.pop() } render() { /** @type {initState["pets"]} */ let state = this.props.state; return () } }My pets:{state.map(pet =>)}
非常容易!我們還添加了兩個(gè)按鈕并指定了點(diǎn)擊處理函數(shù),運(yùn)行體驗(yàn)一下:
打開(kāi) react dev tools 的 Highlight Updates 選項(xiàng),并點(diǎn)擊 push 或 pop 按鈕,可以觀察到視圖更新情況如我們所愿:
空初始數(shù)組與編輯器 intelliSence通常情況下,數(shù)組節(jié)點(diǎn)的初始值是空的。為了實(shí)現(xiàn)編輯器 intelliSence, 我們可以在外面定義一個(gè)元素類型,并注釋這個(gè)數(shù)組節(jié)點(diǎn)的元素為該類型:
const initState = { ... /** @type {[pet]} */ pets: [] } const pet = { id: "id01", name: "Kitty", age: 2 }
你也可以使用泛型的格式來(lái)定義數(shù)組類型: /** @type {Array
上一章我們提到了單實(shí)例組件,是指組件只被使用一次;而我們可以到 PetView 被用于顯示數(shù)組元素,會(huì)被多次使用。我們把這類在多處被使用的組件稱為多實(shí)例組件。多實(shí)例組件內(nèi)部動(dòng)作的處理邏輯由組件實(shí)例的具體位置而定,與單實(shí)例組件的處理模式有差別,我們來(lái)看看。
我們?cè)囍谱饕粋€(gè)每個(gè)寵物視圖中添加兩個(gè)按鈕來(lái)調(diào)整寵物的年齡,我們用兩種傳統(tǒng)方案和pastate方案分別實(shí)現(xiàn):
react 傳統(tǒng)方案 傳統(tǒng)方案1:父組件處理父組件向子組件傳遞綁定index的處理函數(shù):這種模式是把子組件的動(dòng)作處理邏輯實(shí)現(xiàn)在父組件中,然后父組件把動(dòng)作綁定對(duì)應(yīng)的 index 后傳遞給子組件
class PetsView extends PureComponent { ... addAge(index){ state.pets[index].age += 1 } reduceAge(index){ state.pets[index].age -= 1 } render() { /** @type {initState["pets"]} */ let state = this.props.state; return (... { state.map((pet, index) =>) } }this.addAge(index)} // 綁定 index 值,傳遞給子組件 reduceAge={() => this.reduceAge(index)} // 綁定 index 值,傳遞給子組件 />) } ...
class PetView extends PureComponent { render() { /** @type {initState["pets"][0]} */ let state = this.props.state; return () } }{state.name}: {/* 使用已綁定 index 值得動(dòng)作處理函數(shù) */} {state.age} {/* 使用已綁定 index 值得動(dòng)作處理函數(shù) */} years old.
這種模式可以把動(dòng)作的處理統(tǒng)一在一個(gè)組件層級(jí),如果多實(shí)例組件的視圖含義不明確、具有通用性,如自己封裝的 Button 組件等,使用這種動(dòng)作處理模式是最好的。但是如果多實(shí)例組件的含義明顯、不具有通用性,特別是用于顯示數(shù)組元素的情況下,使用這種模式會(huì)引發(fā)多余的渲染過(guò)程。
打開(kāi) react dev tools 的 Highlight Updates 選項(xiàng),點(diǎn)擊幾次 push pet 增加一些元素后,再點(diǎn)擊 + 或 - 按鈕看看組件重新渲染的情況:
可以發(fā)現(xiàn)當(dāng)我們只修改某一個(gè)數(shù)組元素內(nèi)部的值(pet[x].age)時(shí),其他數(shù)組元素也會(huì)被重新渲染。這是因?yàn)?Pet.props.addAge 和 Pet.props.reduceAge 是每次父組件 PetsView 渲染時(shí)都會(huì)重新生成的匿名對(duì)象,PureComponent 以此認(rèn)為組件依賴的數(shù)據(jù)更新了,所以觸發(fā)重新渲染。雖然使用 React.Component 配合 自定義的 shouldComponentUpdate 生命周期函數(shù)可以手動(dòng)解決這個(gè)問(wèn)題,但是每次渲染父組件 PetsView 時(shí)都重新生成一次匿名子組件屬性值,也在消耗運(yùn)算資源。
傳統(tǒng)方案2:子組件結(jié)合 index 實(shí)現(xiàn)父組件向子組件傳遞 index 值:這種模式是父組件向子組件傳遞 index 值,并在子組件內(nèi)部實(shí)現(xiàn)自身的事件處理邏輯,如下:
class PetsView extends PureComponent { ... render() { ... return (... { state.map((pet, index) =>) } }) } ...
class PetView extends PureComponent { // 在子組件實(shí)現(xiàn)動(dòng)作邏輯 // 調(diào)用時(shí)傳遞 index addAge(index){ state.pets[index].age += 1 } // 或函數(shù)自行從 props 獲取 index reduceAge = () => { // 函數(shù)內(nèi)部使用到 this 對(duì)象,使用 xxx = () => {...} 來(lái)定義組件屬性更方便 state.pets[this.props.index].age -= 1 } render() { /** @type {initState["pets"][0]} */ let state = this.props.state; let index = this.props.index; return () } }{state.name}: {/* 使用閉包傳遞 index 值 */} {state.age} {/* 或讓函數(shù)實(shí)現(xiàn)自己去獲取index值 */} years old.
這種模式可以使子組件獲取 index 并處理自身的動(dòng)作邏輯,而且子組件也可以把自身所在的序號(hào)顯示出來(lái),具有較強(qiáng)的靈活性。我們?cè)賮?lái)看看其當(dāng)元素內(nèi)部 state 改變時(shí),組件的重新渲染情況:
我們發(fā)現(xiàn),數(shù)組元素組件可以很好地按需渲染,在渲染數(shù)組元素的情況下這種方法具有較高的運(yùn)行效率。
但是,由于元素組件內(nèi)部操作函數(shù)綁定了唯一位置的 state 操作邏輯,如addAge(index){ state.pets[index].age += 1}。假設(shè)我們還有 state.children 數(shù)組,數(shù)組元素的格式與 state.pets 一樣, 我們要用相同的元素組件來(lái)同時(shí)顯示和操作這兩個(gè)數(shù)組時(shí),這種數(shù)組渲染模式就不適用了。我們可以用第1種方案實(shí)現(xiàn)這種情況的需求,但第1種方案在渲染效率上不是很完美。
pastate 數(shù)組元素操作方案Pastate 的 imState 的每個(gè)節(jié)點(diǎn)本身帶有節(jié)點(diǎn)位置的信息和 store 歸宿信息,我們可以利用這一點(diǎn)來(lái)操作數(shù)組元素!
pastate 方案1:獲取對(duì)于的響應(yīng)式節(jié)點(diǎn)我們使用 getResponsiveState 函數(shù)獲取 imState 對(duì)于的響應(yīng)式 state,如下:
class PetsView extends PureComponent { ... render() { ... return (... { state.map((pet, index) =>) } }) } ...
import {..., getResponsiveState } from "pastate" class PetView extends PureComponent { addAge = () => { /** @type {initState["pets"][0]} */ let pet = getResponsiveState(this.props.state); // 使用 getResponsiveState 獲取響應(yīng)式 state 節(jié)點(diǎn) pet.age += 1 } reduceAge = () => { /** @type {initState["pets"][0]} */ let pet = getResponsiveState(this.props.state); // 使用 getResponsiveState 獲取響應(yīng)式 state 節(jié)點(diǎn) pet.age -= 1 } render() { /** @type {initState["pets"][0]} */ let state = this.props.state; return () } }{state.name}: {state.age} years old.
我們可以看到,子組件通過(guò) getResponsiveState 獲取到當(dāng)前的 props.state 對(duì)應(yīng)的響應(yīng)式 state,從而可以直接對(duì) state 進(jìn)行復(fù)制修改,你無(wú)需知道 props.state 究竟在 store.state 的什么節(jié)點(diǎn)上! 這種模式使得復(fù)用組件可以在多個(gè)不同掛載位置的數(shù)組中使用,而且可以保證很好的渲染性能:
pastate 方案2:使用 imState 操作函數(shù)Pastate 提供個(gè)三個(gè)直接操作 imState 的函數(shù),分別為 set, merge, update。我們來(lái)演示用這些操作函數(shù)來(lái)代替 getResponsiveState 實(shí)現(xiàn)上面操作寵物年齡的功能:
import {..., set, merge, update } from "pastate" class PetView extends PureComponent { addAge = () => { set(this.props.state.age, this.props.state.age + 1); } reduceAge = () => { merge(this.props.state, { age: this.props.state.age - 1 }); } reduceAge_1 = () => { update(this.props.state.age, a => a - 1); } ... }
可見(jiàn),這種 imState 操作函數(shù)的模式也非常簡(jiǎn)單!
使用 pastate 數(shù)組元素操作方案的注意事項(xiàng):當(dāng)操作的 state 節(jié)點(diǎn)的值為 null 或 undefined 時(shí), 只能使用 merge 函數(shù)把新值 merge 到父節(jié)點(diǎn)中,不可以使用 getResponsiveState ,set 或 update。我們?cè)谠O(shè)計(jì) state 結(jié)構(gòu)時(shí),應(yīng)盡量避免使用絕對(duì)空值,我們完全可以用 "", [] 等代替絕對(duì)空值。
下一章,我們來(lái)看看如何在 pastate 中渲染和處理表單元素。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/93803.html
摘要:這一章,我們?cè)谏弦徽碌慕Y(jié)構(gòu)中添加多一些信息,并用多個(gè)組件來(lái)組織應(yīng)用。是的響應(yīng)式影子可以對(duì)任何節(jié)點(diǎn)進(jìn)行直接賦值修改,會(huì)把修改結(jié)果作用到,并異步觸發(fā)視圖更新。因此在中的是對(duì)象而在中的是對(duì)象。 這是 pastate 系列教程的第二章,歡迎關(guān)注,持續(xù)更新。 這一章,我們?cè)谏弦徽碌?state 結(jié)構(gòu)中添加多一些信息,并用多個(gè)組件來(lái)組織 pastate 應(yīng)用。 更新 state 結(jié)構(gòu) 我們把上一章...
摘要:簡(jiǎn)介是什么是一個(gè)響應(yīng)式管理框架,實(shí)現(xiàn)了對(duì)的異步響應(yīng)式管理。可靠性已經(jīng)通過(guò)個(gè)測(cè)試用例的全面測(cè)試,穩(wěn)定可靠。安裝是一個(gè)狀態(tài)管理框架,需要配合使用。 Pastate 簡(jiǎn)介 Pastate 是什么 Pastate 是一個(gè)響應(yīng)式 react state 管理框架,實(shí)現(xiàn)了對(duì) state 的異步響應(yīng)式管理。Pastate 是一個(gè)精益框架,它對(duì)很多高級(jí)概念進(jìn)行了友好封裝,這意味著你不必學(xué)習(xí)一些難以理解...
摘要:宅印前端基于的模式開(kāi)發(fā),我們指定了一套分工明確的并行開(kāi)發(fā)流程。下面通過(guò)一個(gè)蘋果籃子實(shí)例,來(lái)看看整個(gè)應(yīng)用開(kāi)發(fā)流程。容器負(fù)責(zé)接收中的和并發(fā)送大多數(shù)時(shí)候需要和直接連接,容器一般不需要多次使用,比如我們這個(gè)應(yīng)用的蘋果籃子。 前言:在當(dāng)下的前端界,react 和 redux 發(fā)展得如火如荼,react 在 github 的 star 數(shù)達(dá) 42000 +,超過(guò)了 jquery 的 39000+,...
摘要:本文總結(jié)了前端老司機(jī)經(jīng)常問(wèn)題的一些問(wèn)題并結(jié)合個(gè)人總結(jié)給出了比較詳盡的答案。網(wǎng)易阿里騰訊校招社招必備知識(shí)點(diǎn)。此外還有網(wǎng)絡(luò)線程,定時(shí)器任務(wù)線程,文件系統(tǒng)處理線程等等。線程核心是引擎。主線程和工作線程之間的通知機(jī)制叫做事件循環(huán)。 showImg(https://segmentfault.com/img/bVbu4aB?w=300&h=208); 本文總結(jié)了前端老司機(jī)經(jīng)常問(wèn)題的一些問(wèn)題并結(jié)合個(gè)...
閱讀 2862·2021-10-21 09:38
閱讀 2762·2021-10-11 10:59
閱讀 3048·2021-09-27 13:36
閱讀 1668·2021-08-23 09:43
閱讀 802·2019-08-29 14:14
閱讀 3040·2019-08-29 12:13
閱讀 3210·2019-08-29 12:13
閱讀 318·2019-08-26 12:24