Redux联合类型状态下useSelector解构的最优实现方案咨询
Redux状态结构设计困惑:联合类型content vs 扁平结构
最近尝试重新设计Redux状态结构时遇到了瓶颈,拿不准该怎么推进。
最初的扁平状态结构
这种结构简单直观,配合useSelector使用很顺手,items和categories的类型始终固定,无需处理undefined或类型转换问题:
type State = { loading: boolean loaded: boolean items: Array<Item> categories: Array<Category> } const initialState: State = { loading: false, loaded: false, items: [], categories: [], }
修改后的联合类型状态结构
因为需要添加一些仅偶尔使用的额外属性,我决定为每个Redux action单独定义类型,状态结构调整为如下形式,冗余度更低:
type RequestItems = { category: Category; items: Array<Item>; totalCountFromServer: number; } export type RequestItem = { item: Item; } export type RequestCategories = { categories: Array<Category> } type RequestContent = | RequestItem | RequestItems | RequestCategories type State = { loading: boolean; loaded: boolean; content: RequestContent | undefined }
但不确定useSelector能否精确推断出类型,也没找到这种结构的最优使用方式,先后尝试了三种写法:
写法一:本地state中转(冗余但可安全处理undefined)
这种写法需要额外的本地state和useEffect来中转数据,虽然冗余,但能检查content是否为undefined,必要时可返回404页面:
const { content, loading, loaded } = useSelector(state => ({ content: state.suply.content, loading: state.suply.loading, loaded: state.suply.loaded, })) const [items, setItems] = useState<Items[]>([]) const [category, setCategory] = useState<Category>(Category.emptyObject) const [totalCountFromServer, setTotalCountFromServer] = useState<number>() useEffect(() => { if (content) { setItems((content as RequestItems).items) setCategory((content as RequestItems).category) setTotalCountFromServer((content as RequestItems).totalCountFromServer) } }, [content])
写法二:selector内直接类型断言(触发TypeError)
直接在selector里断言content的类型会抛出TypeError,因为content可能为undefined,无法读取其属性:
const { content, loading, loaded } = useSelector(state => ({ items: (state.suply.content as RequestItems).items, category: (state.suply.content as RequestItems).category, totalCountFromServer: (state.suply.content as RequestItems).totalCountFromServer, loading: state.suply.loading, loaded: state.suply.loaded, }))
写法三:解构时类型断言(能运行但不规范)
这种写法可以正常工作,但查阅Stack Overflow后得知,这种解构方式并不符合规范:
const { content, loading, loaded } = useSelector(state => ({ content: state.suply.content, loading: state.suply.loading, loaded: state.suply.loaded, })) const {items, category, totalCountFromServer } = (content as RequestItems);
疑问
现在想请教:使用包含联合类型content的状态结构,有没有更优的实现方式?还是应该回归最初的扁平状态结构?
内容的提问来源于stack exchange,提问作者WichyCake
相关产品推荐
相关产品推荐

