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

NGXS技术问询:能否将数组中的对象拆分至子状态?

解决方案:拆分选中项子状态并保持双向同步

看起来你已经精准抓住了问题的核心——频繁的find()调用和动作耦合确实会影响代码维护性和性能。按照你的需求,我们可以通过拆分出selectedItem子状态,并实现双向同步逻辑来解决这些问题,同时保留原有的数组和选中ID状态。下面是具体的实现步骤:

1. 更新状态模型结构

首先调整你的顶层状态,新增selectedItem子状态来存储当前选中的完整Item对象:

interface ItemsModel {
  listOfItems: Item[]; // 保留原数组,最多10个不同项
  selections: { itemId: number }; // 保留原选中ID状态
  selectedItem: Item | null; // 新增的选中项子状态
}

这样我们就把针对单个Item的操作和数组操作的状态分离开,为后续解耦动作打下基础。

2. 同步选中ID变更到selectedItem

当用户点击切换选中项时,在设置selections.itemId的同时,直接从数组中找到对应Item并更新selectedItem子状态。这样后续操作选中项时就不用反复调用find()了:

@Action(Item.Select)
setSelectedItem({ setState, getState }: StateContext<ItemsModel>, { itemId }: Item.Select) {
  const currentState = getState();
  // 只在切换选中时调用一次find()
  const targetItem = currentState.listOfItems.find(i => i.itemId === itemId) || null;
  
  setState(patch({
    selections: patch({ itemId }),
    selectedItem: targetItem
  }));
}

3. 同步selectedItem修改回原数组

接下来,针对选中项的所有修改动作(比如更新数量、修改属性等),我们可以创建专门的动作来处理,同步更新selectedItem子状态和原数组中的对应项:

首先定义一个更新选中项的动作:

export class UpdateSelectedItem implements Action {
  readonly type = '[Items] Update Selected Item';
  constructor(public payload: Partial<Item>) {}
}

然后在状态类中处理这个动作,同时更新子状态和原数组:

@Action(UpdateSelectedItem)
updateSelectedItem({ setState, getState }: StateContext<ItemsModel>, { payload }: UpdateSelectedItem) {
  const currentState = getState();
  if (!currentState.selectedItem) return; // 无选中项时直接返回

  // 更新选中项子状态
  const updatedSelectedItem = { ...currentState.selectedItem, ...payload };
  // 同步替换原数组中的对应项
  const updatedList = currentState.listOfItems.map(item => 
    item.itemId === updatedSelectedItem.itemId ? updatedSelectedItem : item
  );

  setState(patch({
    listOfItems: updatedList,
    selectedItem: updatedSelectedItem
  }));
}

现在所有针对选中项的修改,都可以通过这个动作来处理,完全和数组的其他操作(比如添加、删除项)解耦。

4. 简化Selector(可选)

既然selectedItem已经是状态的直接属性,原来的getSelectedItem选择器可以直接简化,彻底消除find()调用:

@Selector()
static getSelectedItem(state: ItemsModel): Item | null {
  return state.selectedItem;
}

额外的状态一致性保障

当执行修改数组的动作(比如删除项)时,要同步检查是否影响了选中状态,避免出现无效的selectedItem:

@Action(Item.Delete)
deleteItem({ setState, getState }: StateContext<ItemsModel>, { itemId }: Item.Delete) {
  const currentState = getState();
  const updatedList = currentState.listOfItems.filter(item => item.itemId !== itemId);
  
  let updatedSelectedItem = currentState.selectedItem;
  let updatedSelections = currentState.selections;

  // 如果删除的是当前选中项,重置选中状态
  if (updatedSelectedItem?.itemId === itemId) {
    updatedSelectedItem = null;
    // 可以设置为第一个有效项的ID,或者保持0根据你的业务逻辑
    updatedSelections = { itemId: updatedList[0]?.itemId || 0 };
  }

  setState(patch({
    listOfItems: updatedList,
    selectedItem: updatedSelectedItem,
    selections: updatedSelections
  }));
}

通过这些步骤,你既保留了原有的数组和选中ID状态,又实现了选中项子状态的解耦,同时解决了频繁find()的性能问题,所有针对单个Item的操作都可以独立处理,不再和数组操作耦合。

内容的提问来源于stack exchange,提问作者MikeByte

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 09:52:41