You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 22:43:22