Изменить состояние объектов на селекторе - PullRequest
0 голосов
/ 17 октября 2019

Как вернуть список дерева из селектора, полученного из плоского списка в магазине?

В моем магазине nrgx у меня есть плоский список объектов, используя ngrx/selector, я преобразую этот плоский список в древовидный список. Я только что реализовал immer, который теперь замораживает магазин (что хорошо), однако селектор теперь выбрасывает ERROR TypeError: Cannot assign to read-only property 'children' of object '[object Object]', потому что магазин заморожен. Возможно, я подхожу к этому неправильно.

Я пытался клонировать массив, но свойство только для чтения, похоже, тоже клонировано. Я также пытался клонировать дочерний элемент.

    // ngrx/selector
    export const getAllActionScriptItems = createSelector(featureSelector, state => {
      if (state.items && state.items.length > 0) {
        // Tired cloning the head item.
        const headItem = state.items.find(i => i.isHeader) ;
        const sortedActionScripts = [SortActions(state.items, headItem.id)];

        return sortedActionScripts;
      }
    });


    function SortActions(data: IActionScript[], startingId: string, noActions: boolean = false): IActionScript {


      // Clone the array
      const clonedData = [...data];

      // Tired cloning the top level item
      const topLevelItem = { ...clonedData.find(item => item.id === startingId) };


      const children = GetChildren(clonedData, topLevelItem.id);

      GetChildrensChildren(clonedData, children);

      topLevelItem.children = children;



      return topLevelItem;
    }


    function GetChildren(data: IActionScript[], parentId: string) {

      // return data.filter(item => item.parentId === parentId).sort((a, b) => a.eventPosition - b.eventPosition);
      // Tried cloning the child items
      return [...data.filter(item => item.parentId === parentId).sort((a, b) => a.eventPosition - b.eventPosition)];
    }

    function GetChildrensChildren(data: IActionScript[], children: IActionScript[]) {
      children.forEach(child => {

        // ERROR TypeError: Cannot assign to read only property 'children' of object '[object Object]
        child.children = GetChildren(data, child.id);
        if (child.children && child.children.length > 0) {
          GetChildrensChildren(data, child.children);
        }
      });
    }

1 Ответ

0 голосов
/ 17 октября 2019

Я решил это, снова используя immer, я создал новое состояние для функции createSelector, после прочтения документации produce удаляет свойства только для чтения.

Типизированные шрифты TypeScript автоматически удаляют модификаторы readonly из черновиков и возвращают значение, соответствующее исходному типу. - Здесь

export const getAllActionScriptItems = createSelector(featureSelector, state => {

  if (state.items && state.items.length > 0) {
    const newState = produce(state, draft => {

      const headItem = draft.items.find(i => i.isHeader);
      const sortedActionScripts = [SortActions(draft.items, headItem.id)];
      draft.items = sortedActionScripts;
    });

    return newState.items.find(i => i.isHeader);
  }
});
...