前端數據範式化
前言
現代web應用的飛速發展,特別是數據驅動思想指導下的React、vue等框架的出現,讓我們越來越需要關註數據的組織管理。隨著應用復雜度的提升,如果不對數據進行有效合理的設計拆分,那麽從性能、可維護性等方面來看會逐漸成為一種阻礙。所以我們需要關註前端數據設計。
其實沒有一種很明確的規範告訴我們具體到前端的數據結構應該如何去設計。關系數據庫設計有很多範式,借鑒而不照搬結合前端自身特點,才是好的前端數據範式化的實踐。
範式化
在深入了解數據範式化之前,我們可以先看個例子
舉個栗子:
實際業務中,叠代比較多的業務,我們一般會配置化,即除了業務數據之外將頁面布局展示相關的內容也由接口控制。
那麽後端返回的數據可能如下:
{
info: [
{
key:‘a‘,
txt:‘展示1‘,
value:0
},
{
key:‘b‘,
txt:‘展示2‘,
value:1
}
]
}
這樣響應操作的時候,需要更新每一項的值如果直接修改info這個數組,存在著很大的不便。
如果你說還好,但這樣將就操作之後,提交的時候發現這一大串冗余數據後端也不需要呀,還是要處理value。
此時的數據還不是那麽的復雜,不過層層嵌套的對象見過吧,讓人心頭一驚的數據格式,如果還在上面操作,可能下個叠代你自己都不知道到底該操作哪個字段了。
這時候如果將展示和邏輯相分離,抽出來一個專門的屬性用來存放與後端交互的數據,看起來是簡潔了一些,後期可維護性也增強了不少。
{
info: [
{
key:‘a‘,
txt:‘展示1‘
},
{
key:‘b‘,
txt:‘展示2‘
}
],
values:{
a:0,
b:1
}
}
這樣其實就可以認為是我們提到範式化或者說是扁平化了。具體到前端數據範式化之前 我們來看看數據庫的範式吧
具體到前端數據範式化之前 我們來看看數據庫的範式吧
什麽是範式:
顧名思義,一個規範模式(雖然有點粗暴,但好像就是這麽回事)。
本來想找段定義貼在下面,不過看了看太生硬了,寫下個人見解好了。
第一範式 1NF
表的列具有原子性,不可再分解。
只要是關系型數據庫就滿足1NF
第二範式 2NF
前提是滿足1NF,在1NF的基礎上。每一行或者實例必須唯一可以被區分,即需要我們說的主鍵(key)。
第三範式 3NF
滿足1NF和2NF,且一個數據庫表中不包含已在其他表中包含的非主鍵字段。
也就是說表中不冗余,可以通過關系從其他表中獲取就不要單獨存放了,也就是相關信息可以通過外鍵相關聯。 有個圖表達的很不錯,借來一用:
當然後面還有其他範式這裏就先不提了。
總結一下,範式就是為了減少冗余,提高效率
遵循的範式越高,冗余越小,但也要具體分析,不可一味追求符合範式。
有些時候一昧的追求範式減少冗余,反而會降低數據讀寫的效率,這個時候就要反範式,利用空間來換時間。
redux中的state設計要求
redux針對state的設計也提出了範式化的要求,對於復雜的數據結構,除了數據重復之外,還可能有下面這些問題:
- 當數據在多處冗余後,需要更新時,很難保證所有的數據都進行更新。
- 嵌套的數據意味著 reducer 邏輯嵌套更多、復雜度更高。尤其是在打算更新深層嵌套數據時。
- 不可變的數據在更新時需要狀態樹的祖先數據進行復制和更新,並且新的對象引用會導致與之 connect 的所有 UI 組件都重復 render。盡管要顯示的數據沒有發生任何改變,對深層嵌套的數據對象進行更新也會強制完全無關的 UI 組件重復 render
所以,在 Redux Store 中管理關系數據或嵌套數據的推薦做法是將這一部分視為數據庫,並且將數據按範式化存儲。
有這麽幾點概念:
- 任何類型的數據在 state 中都有自己的 “表”。
- 任何 “數據表” 應將各個項目存儲在對象中,其中每個項目的 ID 作為 key,項目本身作為 value。
- 任何對單個項目的引用都應該根據存儲項目的 ID 來完成。
- ID 數組應該用於排序。
具體實踐-Normalizr
這裏就需要提到Normalizr了,對於復雜數據管理,基本都會提到它。其作用很直白的通過其簡介體現出來:Normalizes nested JSON according to a schema。依據模式規範化的處理json。
其用法這裏就不介紹了,只提供下轉換前後的數據做個對比。有興趣的大家去官網一看便知。
原始數據:
{
"id": "123",
"author": {
"id": "1",
"name": "Paul"
},
"title": "My awesome blog post",
"comments": [
{
"id": "324",
"commenter": {
"id": "2",
"name": "Nicole"
}
}
]
}
轉換後
{
result: "123",
entities: {
"articles": {
"123": {
id: "123",
author: "1",
title: "My awesome blog post",
comments: [ "324" ]
}
},
"users": {
"1": { "id": "1", "name": "Paul" },
"2": { "id": "2", "name": "Nicole" }
},
"comments": {
"324": { id: "324", "commenter": "2" }
}
}
}
這樣的數據就比較符合我們前面redux設計要求了。
結束語
到這裏前端數據的範式化也就介紹的差不多了,一個感悟是js中的數據結構設計何嘗不是數據庫設計,去遵循相應的範式會讓我們的數據結構更加清晰明了。就算開始沒考慮到,隨著業務量級的上升原本結構遇到的問題,開發的時候自然也會去往更優雅的方向去靠,這就是進步的過程。
不過還是那句話,要基於實際情況來看待,不要盲目引入,化簡為繁不是一種值得稱贊的做法。
通篇文章為個人見解,拋磚引玉有不對的地方歡迎指出
參考文章:
https://blog.csdn.net/qq_35401191/article/details/82760301
https://zhuanlan.zhihu.com/p/36487766
http://cn.redux.js.org/docs/recipes/reducers/NormalizingStateShape.html
前端數據範式化