我正在开发一个分为多个功能的音乐应用程序:
library
:显示可用内容,并允许用户浏览艺术家和专辑,并播放一首或几首曲目。州看起来像这样:
图书馆{ tracksById:{...} albumsById:{...} artistsById:{...} 专辑:[] 艺术家:[] }
player
:播放音乐的部分。只包含要播放的所有曲目的数组。还会显示要播放的曲目列表
等;问题是我想在所有功能之间共享tracksById
,albumsById
和artistsById
,因为每个相册都有一个艺术家属性,但这个属性只是一个id,所以如果我想要要在播放列表中的曲目名称附近显示艺术家姓名,我需要获取艺术家,并将其放入我的商店。我可以简单地将它们连接起来:
@connect(createStructuredSelector({
player: (state) => state.player,
library: (state:) => state.library
}), (dispatch) => ({
actions: bindActionCreators(actions, dispatch)
}))
然后在我的播放列表视图中:
<div className="artist-name">{this.library.artistsById[track.artist].name}</div>
然而,这增加了特征之间的耦合,我发现它击败了多个减速器的目的。
另一种方法是创建一个新功能content
,它只包含所需的动作和byId属性,以及最小的减速器,并且这个功能将由其他功能共享。但是,这意味着我必须为每个组件content
添加一个新的道具,我需要添加操作。
我还可以创建一个服务,甚至可能是一个带有reducer和actions对象的函数,并添加一个逻辑,使它能够获取艺术家,专辑和曲目并将它们保存在商店中。我真的很喜欢这个想法,因为它减少了耦合,但是,它意味着我的状态中的重复数据,这意味着使用更多的内存。
我不是在寻找最好的方法,只是想知道是否还有其他方法以及每种方法的优缺点
答案 0 :(得分:0)
我很确定我不完全理解你的问题,但我会分享一些想法。您是否尝试避免重复查询或重复的状态数据?
这一点重复:
{this.library.artistsById[track.artist].name}
library.artists
是对象而不是数组,则变得不必要。假设1和2是艺术家ID,artists
将使用艺术家ID作为对象中的键:
{
1: {name: 'Bob Marley', ...etc},
2: {name: 'Damien Marley', ...etc}
}
这样,您只需使用ID:
即可从library.artists
获取艺术家信息
{this.library.artists[track.artistId].name}
但你真正想要的是getArtistById(state, artistId){}
,你的reducer代码文件中的选择器函数。这使您可以随时重新排列状态,并且您的视图组件都不会受到影响。如果artists
是关键字为艺术家ID的对象,则实现可能如下所示:
getArtistById(state, artistId){
return state.library.artists[artistId]
}
我同意你的看法,即访问library.artistsById[track.artist].name
会增加不必要的耦合。我永远不会将知道高级状态形状的代码放入视图组件中。
对于带有艺术家列表的示例播放列表视图,播放列表视图中的每个项目都是其自己的微小组件。容器看起来像这样:
import { getArtistById } from '../reducers/root-reducer'
const mapStateToProps = (state) => {
const artist = getArtistById(state.library)
return { artistName: artist ? artist.name : '' }
}
...
微小视图组件看起来像:
render() {
const {artistName} = this.props
return <div className="artist-name">{artistName}</div>
}
您可能过早地进行了优化。即使您将artists
和albums
保留为数组,您的选择器功能也可以在数组中搜索ID。从一个只包含{ artists: [], albums: [], tracks:[] }
的状态获取每个id的函数应该非常快,直到库变得非常庞大。