Zustand+Immer+TypeScript:如何简化深层嵌套状态的空值判断?
问题描述
我在项目中使用Zustand结合Immer创建状态仓库,状态是深度嵌套的Series类型:
{ id: 0, metaData: {}, multipleGroupsRequireApproval: false, approvalStatus: ApprovalStatus.NO_APPROVAL, variants: Variant[] | null, items: Item[] | null, }[],
组件首次渲染时会从后端获取同格式数据并设置到状态中,因此接口返回的数据存在大量null值。
我编写了一个修改系列审批状态的方法:
setApprovalForCurrentSeries(seriesIndex, variantIndex) { set( produce((state: SeriesStore) => { const series = state.seriesArray[seriesIndex] if (series?.variants) { series.approvalStatus = ApprovalStatus.HAS_APPROVAL const variant = series.variants[variantIndex] if (variant) { variant.isApproved = true } } const items = series?.items|| [] items.forEach((item) => { const itemVariants = item.variants || [] const itemVariant = itemVariants[variantIndex] if (itemVariant) { itemVariant.isApproved = true } }) }), ) },
后续还会新增多个修改variants或items的方法,想知道能不能提取这些空值判断的if语句部分,实现直接访问目标对象?
解决方案
当然可以,下面提供几种实用方案来简化空值判断,避免重复代码:
方案一:封装通用安全访问工具函数
编写针对性的工具函数,统一处理空值检查逻辑,后续所有状态修改方法都可以复用:
// 安全获取指定索引的series,不存在则返回null const getSeries = (state: SeriesStore, index: number) => state.seriesArray[index] ?? null // 安全获取series下指定索引的variant,不存在则返回null const getSeriesVariant = (series: Series | null, index: number) => series?.variants?.[index] ?? null // 安全获取item下指定索引的variant,不存在则返回null const getItemVariant = (item: Item, index: number) => item.variants?.[index] ?? null // 安全获取series下的items数组,为null则返回空数组 const getSeriesItems = (series: Series | null) => series?.items ?? []
简化后的状态修改方法:
setApprovalForCurrentSeries(seriesIndex, variantIndex) { set( produce((state: SeriesStore) => { const series = getSeries(state, seriesIndex) if (!series) return series.approvalStatus = ApprovalStatus.HAS_APPROVAL const seriesVariant = getSeriesVariant(series, variantIndex) if (seriesVariant) seriesVariant.isApproved = true getSeriesItems(series).forEach(item => { const itemVariant = getItemVariant(item, variantIndex) if (itemVariant) itemVariant.isApproved = true }) }), ) },
方案二:用可选链简化单行判断
如果不想额外封装工具函数,可以结合可选链?.和逻辑与&&,把空值判断简化到一行:
setApprovalForCurrentSeries(seriesIndex, variantIndex) { set( produce((state: SeriesStore) => { const series = state.seriesArray[seriesIndex] if (!series) return series.approvalStatus = ApprovalStatus.HAS_APPROVAL // 存在目标variant则赋值,不存在则跳过 series.variants?.[variantIndex] && (series.variants[variantIndex].isApproved = true) // 处理items的逻辑同理 series.items?.forEach(item => { item.variants?.[variantIndex] && (item.variants[variantIndex].isApproved = true) }) }), ) },
方案三:数据入库时统一转换(根源解决)
如果后端返回的空值可以提前处理,建议在获取数据后统一把null数组转为空数组,从根源上消除空值判断:
// 示例:获取后端数据并预处理 const fetchSeriesData = async () => { const rawData = await api.get('/series') return rawData.map(series => ({ ...series, variants: series.variants ?? [], items: series.items ?? [] })) }
预处理后,所有状态修改方法都可以直接访问series.variants和series.items,完全不需要空值判断。
内容的提问来源于stack exchange,提问作者MrMurman
相关产品推荐
相关产品推荐

