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