這篇文章給大家分享的內容是關於Pastate.js 響應式框架之多元件應用 ,有著一定的參考價值,有需要的朋友可以參考一下
這是pastate 系列教學的第二章,歡迎關注,持續更新。
這一章,我們在上一章的 state 結構中加入多一些訊息,並用多個元件來組織 pastate 應用程式。
我們把上一章的個人基本資訊資料包裝為state.basicInfo
屬性的對象,並向state
中新增address
屬性,儲存個人位址資訊:
1 2 3 4 5 6 7 8 9 10 11 |
|
由於JavaScript 語言的限制,pastate 無法偵測到透過賦值來為物件新增屬性,以自動將新屬性轉換為回應式節點。所以你應該在 initState 中把需要用到的 state 屬性都定義出來,把屬性值初始化為 null 或空數組都是可以的。以下是個錯誤的範例:
1 2 3 4 5 6 7 8 |
|
即使支援這個特性,它也會讓開發者難以完全掌握state 的結構,導致應用程式難以開發與維護,所以我們應該在initState裡對state 的結構進行完整的定義。
我們先用簡單暫時的方式來建構子元件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
1 2 3 4 5 6 7 8 9 10 11 |
|
可以看到,BasicInfoView 元件直接引用store .state.basicInfo 的值,AddressView 元件直接引用store.state.address 的值。接著修改原來的AppView 父元件,把這兩個子元件巢狀進去,同時增加一個方法來修改address.city
的值:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
完成!讓我們運行一下:
點擊按鈕,看起來一切正常!我們透過 Chrome 的 react dev tools 來觀察一下當 state 改變時,各個元件的渲染情況。開啟瀏覽器的開發者工具,選擇 react 標籤,勾選上 Highlight Updates, 這時當元件重新渲染時,會被帶有顏色的方塊框起來。
我們點選頁面上decrease age
按鈕試試,元件重新渲染的結果如下:
我們可以發現,當只有state.basicInfo.age 改變時,AppView、BasicInfoView 和AddressView 3個元件都會被重新渲染,即使AddressView 所引用的資料沒有發生任何改變!這是react 多元件渲染的通常情況,當應用元件簡單、嵌套層級不多時,我們不會感覺到這種模式會帶來什麼明顯的影響;但是當應用元件的嵌套關係變得比較複雜的時候,會帶來性能隱患,我們需要來關注這個問題。
先介紹一下store 中的兩個不同的state:store.imState 和store.state ,你可以試著了解:
store.imState 是應用程式狀態的資料實體,它被pastate 使用immutable 的機制來管理,當節點的內容更新時,該節點的所有祖先的「引用」都會被更新。 imState 的每個節點值除了 null 或 undefined 外,都是包裝類型(String, Number, Boolean, Object, Array)。
store.state 是store.imState 的響應式陰影
, 可以直接對store.state 任何節點進行賦值修改,pastate 會把修改結果作用到store.imState,並非同步觸發視圖更新。
或簡化為以下兩點:
#store.imState 用來渲染視圖
store.state 用來操作資料
這兩個概念對於沒有使用過redux 和沒了解過vue.js 原理的人來說可能有點難懂。不過沒關係,不理解這兩個概念並不妨礙你使用 pastate,你可以在使用 pastate 的過程中完全感覺不到 imState 的存在。 pastate 的理念就是封裝複雜概念,讓你可以用簡單的方式去實現複雜的功能。
如果你想要理解 pastate 的詳細原理,可以查看原理章節。
當一個component 與store 連接時,store 會把imState 傳遞到component 的props
.state 中,因此我們可以在AppView 元件的props 中接收state,同時把AppView 元件的基類改為react 純元件PureComponent,這樣就開啟了元件按需渲染效果:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
注意上面代码的第3点注释,我们把 state 数据的子节点通过 props 传递给子组件: <BasicInfoView state={state.basicInfo}/>
。对于不直接与 store 直接连接的子组件,我们同样也需要修改为从
props 获取 state, 并把组件的基类改成 PureComponent:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
可以看到,分配到子组件的 props 中的 state 是 根state 的子节点。因此在 BasicInfoView 中的 this.props.state 是 basicInfo 对象, 而在 AddressView 中的 this.props.state 是 address 对象。
完成!我们来看看运行效果!
点击 decrease age
按钮或 increase age
按钮,我们看到的组件重新渲染情况是:
点击 change city
按钮,我们看到的组件重新渲染情况是:
Amazing!可以看到当我们点击按钮改变 state 节点时,只有引用被改变的 state 节点的组件才会进行重新渲染, 我们成功地实现了多组件按需渲染的效果!当应用具有大量不与 store 直接连接的子组件时,这种按需渲染的策略可以大幅提高应用的渲染性能。
从 props 中接收到的 state 的每个节点都是特殊的包装类型 , 当需要在 if(...)
语句或 ... ? A : B
使用其布尔值结果时, 需要使用 ==
进行显式比较来获取,如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
React 的 PureComponent 会在渲染前对新的 props / state 与老的 props / state 进行浅层比较( shallow comparison),仅当发现 props / state 发生改变时,才执行重新渲染。浅层比较即是比较 props / state 的根级属性值是否改变,如果属性值是数组 / 对象类型,比较的结果使其引用是否相等:
1 2 3 4 |
|
1 2 3 4 |
|
Pastate 符合 immutable data 规范的 state 数据,可以确保当某个 state 节点改变时,其祖先节点的引用都会进行更新,所以可以配合使用 PureComponent 实现高效的按需渲染。
按需渲染时需要对 state 的结构进行模块化设计,如果把所有的属性都放在 state 根节点上,就没法实现按需渲染了:
1 2 3 4 5 6 7 8 |
|
当然,只有当应用的 state 比较复杂且对 state 的操作比较繁多时候,才会体现按需渲染对性能的提升;当应用比较简单的时候,不一定要对 state 和视图进行太详细的划分。
同样,我们可以使用 jsDoc 注释让子组件中 state 的具有智能提示,如下:
1 2 3 4 5 6 7 |
|
1 2 3 4 5 6 7 |
|
请使用 xxx['xxx'] 的格式指明对象的子节点: /** @type {initState['address']} */
。在 vs code 里,暂时无法使用 xxx.xxx 的嵌套格式指定一个变量的类型。
如果某组件只在视图中出现一次,那么这种组件被称为单实例组件。这种组件可以把对子组件设计的 state 操作函数简单地封装在子组件内部,提高组件的内聚性,便于维护管理。下面以 BasicInfoView 为例,把操作按钮移入子组件,并把两个操作函数移入子组件:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
同样,你也可以对 AddressView 做类似的处理。
下一章, 我们将会介绍如何在 pastate 中渲染和操作 state 中的数组。
这是 pastate 系列教程的第二章,欢迎关注,持续更新。
这一章,我们在上一章的 state 结构中添加多一些信息,并用多个组件来组织 pastate 应用。
相关推荐:
Pastate.js 之响应式 react state 管理框架
以上是Pastate.js 響應式框架多重元件應用的詳細內容。更多資訊請關注PHP中文網其他相關文章!