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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 08:49:55