摘要:這一章,我們在上一章的結構中添加多一些信息,并用多個組件來組織應用。是的響應式影子可以對任何節(jié)點進行直接賦值修改,會把修改結果作用到,并異步觸發(fā)視圖更新。因此在中的是對象而在中的是對象。
這是 pastate 系列教程的第二章,歡迎關注,持續(xù)更新。
這一章,我們在上一章的 state 結構中添加多一些信息,并用多個組件來組織 pastate 應用。
更新 state 結構我們把上一章的個人基本信息數(shù)據(jù)包裝為 state.basicInfo 屬性的對象,并向 state 中添加 address 屬性,保存?zhèn)€人地址信息:
const initState = { basicInfo: { name: "Peter", isBoy: true, age: 10 }, address: { country: "China", city: "Guangzhou" } }
由于 JavaScript 語言的限制,pastate 不能檢測到通過賦值來為對象添加新屬性,以自動把新屬性轉化為響應式節(jié)點。所以你應該在 initState 中把需要用到的 state 屬性都定義出來,把屬性值初始化為 null 或空數(shù)組都是可以的。下面是個錯誤的例子:
const initState = { basicInfo: ..., address: ... } const store = new Pastore(initState) const state = store.state state.hobby = "coding" // 錯誤,state.hobby 屬性不具有受 pastate 控制,不具有響應式特點
即使支持這種特性,它也會使開發(fā)者難以完全把握 state 的結構,導致應用難以開發(fā)和維護,所以我們應該在 initState 里對 state 的結構進行完整的定義。
分別開發(fā) basicInfo 和 address 的視圖組件我們先使用一種簡單臨時的方式來構建子組件:
... /** @type {initState} */ const state = store.state; class BasicInfoView extends Component { render(){ return (Basic info:) } }
My name is {state.basicInfo.name}.
I am a {state.basicInfo.isBoy == true ? "boy" : "girl"}.
I am {state.basicInfo.age} years old.
class AddressView extends Component { render(){ return (Address:) } }
My country is {state.address.country}.
My city is {state.address.city}.
可以看到,BasicInfoView 組件直接引用 store.state.basicInfo 的值,AddressView 組件直接引用 store.state.address 的值。接著修改原來的 AppView 父組件,把這兩個子組件嵌套進去,同時增加一個方法來修改 address.city 的值:
... class AppView extends Component { increaseAge(){ state.basicInfo.age += 1 } decreaseAge(){ state.basicInfo.age -= 1 } changeCity(){ state.address.city += "!" } render() { return () } } ...
完成!讓我們運行一下:
點擊按鈕,看起來一切正常!我們通過 Chrome 的 react dev tools 來觀察一下當 state 改變時,各個組件的渲染情況。打開瀏覽器的開發(fā)者工具,選擇 react 標簽,勾選上 Highlight Updates, 這時當組件重新渲染時,會被帶顏色的方框框起來。
我們點擊頁面上 decrease age 按鈕試試,組件重新渲染的結果如下:
我們可以發(fā)現(xiàn),當只有 state.basicInfo.age 更改時,AppView、BasicInfoView 和 AddressView 3個組件都會被重新渲染,即使 AddressView 所引用的數(shù)據(jù)沒有發(fā)生任何改變!這是 react 多組件渲染的通常情況,當應用組件簡單、嵌套層級不多時,我們不會感覺到這種模式會帶來什么明顯的影響;但是當應用組件的嵌套關系變得比較復雜的時候,會帶來性能隱患,我們需要來關注這個問題。
store.imState 與 store.state先介紹一下 store 中的兩個不同的 state:store.imState 和 store.state ,你可以嘗試了解一下:
store.imState 是應用狀態(tài)的數(shù)據(jù)實體,它被 pastate 使用 immutable 的機制進行管理,當節(jié)點的內(nèi)容更新時,該節(jié)點的所有祖先的“引用”都會被更新。imState 的每個節(jié)點值除了 null 或 undefined 外,都是包裝類型(String, Number, Boolean, Object, Array)。
store.state 是 store.imState 的 響應式影子, 可以對 store.state 任何節(jié)點進行直接賦值修改,pastate 會把修改結果作用到 store.imState,并異步觸發(fā)視圖更新。
或者簡化為以下兩點:
store.imState 用來渲染視圖
store.state 用來操作數(shù)據(jù)
這兩個概念對于沒有使用過 redux 和沒了解過 vue.js 原理的人來說可能有點難以理解。不過沒關系,不理解這兩個概念并不妨礙你使用 pastate,你可以在使用 pastate 的過程中完全感覺不到 imState 的存在。pastate 的理念就是封裝復雜概念,讓你可以用一種簡單的方式去實現(xiàn)復雜的功能。
如果你想要理解 pastate 的詳細原理,可以查看原理章節(jié)。
使用 props 接收 imState,實現(xiàn)組件的按需渲染當一個 component 與 store 連接時,store 會把 imState 傳遞到 component 的 props
.state 中,因此我們可以在 AppView 組件的 props 中接收 state,同時把 AppView 組件的基類改為 react 純組件 PureComponent,這樣就開啟了組件按需渲染效果:
import React, { PureComponent } from "react"; // 1. 改用 PureComponent 代替 Component ... class AppView extends PureComponent { // 1. 改用 PureComponent ... render() { /** @type {initState} */ let state = this.props.state; // 2. 從 props 接收 state return ({/** 3. 把 state 的子節(jié)點傳遞給對于的子組件 */}) } } ......
注意上面代碼的第3點注釋,我們把 state 數(shù)據(jù)的子節(jié)點通過 props 傳遞給子組件:
props 獲取 state, 并把組件的基類改成 PureComponent:
class BasicInfoView extends PureComponent { // 1. 基類改為 PureComponent render(){ let state = this.props.state; // 2. 從 props 接收 state return (Basic info:) } }
{/** 3. 這里的 state 是 basicInfo 對象 */} My name is {state.name}.
I am a {state.isBoy == true ? "boy" : "girl"}.
I am {state.age} years old.
class AddressView extends PureComponent { // 1. 基類改為 PureComponent render(){ let state = this.props.state; // 2. 從 props 接收 state return (Address:) } }
{/** 3. 這里的 state 是 address 對象 */} My country is {state.country}.
My city is {state.city}.
可以看到,分配到子組件的 props 中的 state 是 根state 的子節(jié)點。因此在 BasicInfoView 中的 this.props.state 是 basicInfo 對象, 而在 AddressView 中的 this.props.state 是 address 對象。
完成!我們來看看運行效果!
點擊 decrease age 按鈕或 increase age 按鈕,我們看到的組件重新渲染情況是:
點擊 change city 按鈕,我們看到的組件重新渲染情況是:
Amazing!可以看到當我們點擊按鈕改變 state 節(jié)點時,只有引用被改變的 state 節(jié)點的組件才會進行重新渲染, 我們成功地實現(xiàn)了多組件按需渲染的效果!當應用具有大量不與 store 直接連接的子組件時,這種按需渲染的策略可以大幅提高應用的渲染性能。
使用 imState 渲染視圖的注意事項從 props 中接收到的 state 的每個節(jié)點都是特殊的包裝類型 , 當需要在 if(...) 語句或 ... ? A : B 使用其布爾值結果時, 需要使用 == 進行顯式比較來獲取,如下
class BasicInfoView extends PureComponent { render() { /** @type {initState["basicInfo"]} */ let state = this.props.state; return (了解 PureComponent{state.isBoy == true ? "boy" : "girl"} {/* 正確 */} {state.isBoy ? "boy" : "girl"} {/* 錯誤 */} {state.age != 0 ? "Not 0" : "0"} {/* 正確 */} {state.age ? "Not 0" : "0"} {/* 錯誤 */}) } }
React 的 PureComponent 會在渲染前對新的 props / state 與老的 props / state 進行淺層比較( shallow comparison),僅當發(fā)現(xiàn) props / state 發(fā)生改變時,才執(zhí)行重新渲染。淺層比較即是比較 props / state 的根級屬性值是否改變,如果屬性值是數(shù)組 / 對象類型,比較的結果使其引用是否相等:
console.log(["a"] == ["a"]) // 結果是 false let a = ["a"] console.log(a == a) // 結果是 true
console.log({a: "a"} == {a: "a"}) // 結果是 false let a = {a: "a"} console.log(a == a) // 結果是 true
Pastate 符合 immutable data 規(guī)范的 state 數(shù)據(jù),可以確保當某個 state 節(jié)點改變時,其祖先節(jié)點的引用都會進行更新,所以可以配合使用 PureComponent 實現(xiàn)高效的按需渲染。
按需渲染時需要對 state 的結構進行模塊化設計,如果把所有的屬性都放在 state 根節(jié)點上,就沒法實現(xiàn)按需渲染了:
// 注意:這樣的 state 設計無法實現(xiàn)子組件的按需渲染 initState = { name: "Peter", isBoy: true, age: 10, country: "China", city: "Guangzhou" }
當然,只有當應用的 state 比較復雜且對 state 的操作比較繁多時候,才會體現(xiàn)按需渲染對性能的提升;當應用比較簡單的時候,不一定要對 state 和視圖進行太詳細的劃分。
子組件 state 的 intelliSense同樣,我們可以使用 jsDoc 注釋讓子組件中 state 的具有智能提示,如下:
class BasicInfoView extends PureComponent { render(){ /** @type {initState["basicInfo"]} */ let state = this.props.state; ... } }
class AddressView extends PureComponent { render(){ /** @type {initState["address"]} */ let state = this.props.state; ... } }
請使用 xxx["xxx"] 的格式指明對象的子節(jié)點: /** @type {initState["address"]} */。在 vs code 里,暫時無法使用 xxx.xxx 的嵌套格式指定一個變量的類型。
單實例子組件如果某組件只在視圖中出現(xiàn)一次,那么這種組件被稱為單實例組件。這種組件可以把對子組件設計的 state 操作函數(shù)簡單地封裝在子組件內(nèi)部,提高組件的內(nèi)聚性,便于維護管理。下面以 BasicInfoView 為例,把操作按鈕移入子組件,并把兩個操作函數(shù)移入子組件:
... class BasicInfoView extends PureComponent { increaseAge(){ state.basicInfo.age += 1 } decreaseAge(){ state.basicInfo.age -= 1 } render(){ /** @type {initState["basicInfo"]} */ let state = this.props.state; return (...) } } ...
同樣,你也可以對 AddressView 做類似的處理。
下一章, 我們將會介紹如何在 pastate 中渲染和操作 state 中的數(shù)組。
文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/93728.html
摘要:但是如果多實例組件的含義明顯不具有通用性,特別是用于顯示數(shù)組元素的情況下,使用這種模式會引發(fā)多余的渲染過程。假設我們還有數(shù)組,數(shù)組元素的格式與一樣我們要用相同的元素組件來同時顯示和操作這兩個數(shù)組時,這種數(shù)組渲染模式就不適用了。 這是 Pastate.js 響應式 react state 管理框架系列教程的第三章,歡迎關注,持續(xù)更新。 這一章我們來看看在 pastate 中如何渲染和處理...
摘要:簡介是什么是一個響應式管理框架,實現(xiàn)了對的異步響應式管理。可靠性已經(jīng)通過個測試用例的全面測試,穩(wěn)定可靠。安裝是一個狀態(tài)管理框架,需要配合使用。 Pastate 簡介 Pastate 是什么 Pastate 是一個響應式 react state 管理框架,實現(xiàn)了對 state 的異步響應式管理。Pastate 是一個精益框架,它對很多高級概念進行了友好封裝,這意味著你不必學習一些難以理解...
摘要:響應式編程是基于異步和事件驅動的非阻塞程序,只是垂直通過在內(nèi)啟動少量線程擴展,而不是水平通過集群擴展。三特性常用的生產(chǎn)的特性如下響應式編程模型適用性內(nèi)嵌容器組件還有對日志消息測試及擴展等支持。 摘要: 原創(chuàng)出處 https://www.bysocket.com 「公眾號:泥瓦匠BYSocket 」歡迎關注和轉載,保留摘要,謝謝! 02:WebFlux 快速入門實踐 文章工程: JDK...
摘要:五六月份推薦集合查看最新的請點擊集前端最近很火的框架資源定時更新,歡迎一下。蘇幕遮燎沈香宋周邦彥燎沈香,消溽暑。鳥雀呼晴,侵曉窺檐語。葉上初陽乾宿雨,水面清圓,一一風荷舉。家住吳門,久作長安旅。五月漁郎相憶否。小楫輕舟,夢入芙蓉浦。 五、六月份推薦集合 查看github最新的Vue weekly;請::點擊::集web前端最近很火的vue2框架資源;定時更新,歡迎 Star 一下。 蘇...
閱讀 3011·2021-10-27 14:15
閱讀 2999·2021-09-07 10:18
閱讀 1320·2019-08-30 15:53
閱讀 1570·2019-08-26 18:18
閱讀 3373·2019-08-26 12:15
閱讀 3460·2019-08-26 10:43
閱讀 654·2019-08-23 16:43
閱讀 2207·2019-08-23 15:27