發(fā)布于:2021-02-01 15:10:20
0
335
0
所有前端開(kāi)發(fā)人員遲早都需要將關(guān)系數(shù)據(jù)保存在Redux存儲(chǔ)中。
數(shù)據(jù)
無(wú)論它們來(lái)自api還是靜態(tài)有效負(fù)載,基于關(guān)系數(shù)據(jù)庫(kù)與否,數(shù)據(jù)之間都有關(guān)系。
我們將定義資源所有可能與其他資源有關(guān)系的數(shù)據(jù)類(lèi)型。
示例資源可以是我們個(gè)人博客上的一篇文章。
這個(gè)帖子將與作者有1:1的關(guān)系(從帖子的角度來(lái)看,我們將看到一個(gè)作者將與帖子有1:N的關(guān)系),與評(píng)論有1:N的關(guān)系。
低效的結(jié)構(gòu)
假設(shè)我們的個(gè)人博客應(yīng)該只提供一個(gè)帖子列表和每個(gè)帖子的詳細(xì)頁(yè)面。
對(duì)于這個(gè)具體的例子,我們可以在Redux存儲(chǔ)中有一個(gè)一級(jí)鍵,其中包含按id索引的所有文章。在每個(gè)文章中,我們可以嵌套作者的數(shù)據(jù)和評(píng)論。
const store = {
posts: {
'p123': {
id: 'p123',
title: 'Best React pattern in the world!',
author: {
id: 'a123',
name: 'Francesco',
email: 'name.surname@gmail.com',
},
comments: {
'c123': {
id: 'c123',
body: 'Best article ever!',
},
'c124': {
id: 'c124',
body: 'Best article ever ever!',
},
}
},
}
}
// And so on, you get the point
如果我想為作者的個(gè)人資料創(chuàng)建一個(gè)包含他文章列表的頁(yè)面,就會(huì)出現(xiàn)這個(gè)問(wèn)題。
以Redux選擇器為例,我們可以這樣檢索所需的數(shù)據(jù):
// This returns an array of posts
const getPostsByAuthor = authorId => state => (
Object.values(state.posts).filter(post => post.author.id === authorId)
)
// And you'd call this selector like this:
const state = store.getState()
const postsByAuthor = getPostsByAuthor('a123')(state) // [...]
但是,如果能夠得到我們需要的東西,效率會(huì)特別低:每次我們都應(yīng)該瀏覽所有的帖子。
加權(quán)結(jié)構(gòu)
加權(quán)結(jié)構(gòu)可以是關(guān)系數(shù)據(jù)庫(kù)中假設(shè)表的1:1表示。
const store = {
posts: {
'p123': {
id: 'p123',
title: 'Best React pattern in the world!',
author: 'a123',
},
},
author_posts: {
'a123': ['p123'],
},
authors: {
'a123': {
id: 'a123',
name: 'Francesco',
email: 'name.surname@gmail.com',
}
},
post_comments: {
'p123': ['c123', 'c124'],
},
comments: {
'c123': {
id: 'c123',
body: 'Best article ever!',
post: 'p123',
},
'c124': {
id: 'c124',
body: 'Best article ever ever!',
post: 'p123',
},
},
}
在本例中,我們消除了嵌套問(wèn)題。但是,我們?yōu)镽edux商店添加了兩個(gè)新的一級(jí)密鑰。
這種方法并非完全錯(cuò)誤,但隨著應(yīng)用程序的增長(zhǎng),可能很難有效地管理所有關(guān)系。
如果資源量有限,這可能是一種有用的方法。但是,如果資源量有限,我們可能并不真正需要Redux,這也是事實(shí)。
高效的結(jié)構(gòu)
按照Firebase的建議,我們可以為自己保存一些一級(jí)密鑰:
const store = {
posts: {
data: {
'p123': {
id: 'p123',
title: 'Best React pattern in the world!',
author: 'a123',
},
},
comments: {
'p123': ['c123', 'c124'],
},
},
authors: {
data: {
'a123': {
id: 'a123',
name: 'Francesco',
email: 'name.surname@gmail.com',
},
},
posts: {
'a123': ['p123'],
},
},
comments: {
data: {
'c123': {
id: 'c123',
body: 'Best article ever!',
post: 'p123',
},
'c124': {
id: 'c124',
body: 'Best article ever ever!',
post: 'p123',
},
},
},
}
與Firebase不同,我們不會(huì)用“占位符”來(lái)嵌套關(guān)系。
相反,我們將第一級(jí)密鑰組織為小的第二級(jí)存儲(chǔ)容器。
對(duì)于reducers
和combineReducers
函數(shù),您是否有類(lèi)似的想法?同樣的邏輯:我們將我們的全局對(duì)象減少到最小的可表示部分。
如何構(gòu)造選擇器
在構(gòu)建了我們的Redux商店之后,您可能會(huì)想到的第一個(gè)問(wèn)題是:如何獲取這些數(shù)據(jù)?
下面是一些簡(jiǎn)單的選擇器。
// Base data
const selectAuthors = state => Object.values(state.authors.data)
const selectAuthor = id => state => state.authors.data[id]
const selectPosts = state => Object.values(state.posts.data)
const selectPost = id => state => state.posts.data[id]
// Totally useless
const selectComments = state => Object.values(state.comments.data)
// Maybe useless
const selectComment = id => state => state.comments.data[id]
// Relations
const selectAuthorPosts = authorId => state => {
const authorPosts = state.authors.posts[authorId] || []
return authorPosts.map(postId => selectPost(postId)(state))
}
const selectPostComments = postId => state => {
const postComments = state.posts.comments[postId] || []
return postComments.map(commentId => selectComment(commentId)(state))
}
結(jié)論
現(xiàn)在您可以構(gòu)造一個(gè)Redux存儲(chǔ)來(lái)保存關(guān)系數(shù)據(jù)。在某些情況下,它可能有些過(guò)分,但在處理更復(fù)雜的應(yīng)用程序時(shí)會(huì)派上用場(chǎng)。
作者介紹
熱門(mén)博客推薦