Odtwarzanie drzewa z łańcuchowym update'owaniem property.

0

Mamy prostą strukturę która odzwierciedla Menu. Najprostszy model danych to:

export interface Node {
    nodes: Node[] | null; // albo Node[] albo null
    expanded: boolean;
    url: string | null;
}

I teraz w sytuacji gdy url któregoś z liści odpowiada jakiemuś konkretnemu url, trzeba zwrócić nowy Node w którym wszystkie Node są w sposób przechodni rodzicami dla danego Node. Nie mogę update'ować starego ze względu na fakt, że potrzebuję zupełnie nowych obiektów. Kod który mam (okrojony, bez nullecheków, zrobiony pod konkretny przykład):

function expandLeaves(node: Node, url: string): Node {
    const newLeaves = createNewLeaves(node.nodes!, url); // ! po zmiennej mówi kompilatorowi, że tam na 100% nulla nie będzie

    return {
        ...node,
        nodes: newLeaves,
        expanded: newLeaves.some(leaf => leaf.expanded)
    }
}


function createNewLeaves(nodes: Node[], url: string): Node[] {
    return nodes.map(node => {
        const expanded = node.nodes?.some(leaf => leaf.expanded) || node.url === url; 
        const newLeaves: Node[] | null = node.nodes ? createNewLeaves(node.nodes, url) : null;
        return {
            ...node,
            nodes: newLeaves,
            expanded: expanded
        }
    })
}

Przykład:

{
   "expanded":false,
   "url":null,
   "nodes":[
      {
         "url":"11",
         "expanded":false,
         "nodes":[
            {
               "expanded":false,
               "url":"url"
            }
         ]
      }
   ]
}

Output:

{
   "expanded":false, //powinno być true
   "url":null,
   "nodes":[
      {
         "url":"11",
         "expanded":false, //powinno być true
         "nodes":[
            {
               "expanded":true,
               "url":"some-url",
               "nodes":null
            }
         ]
      }
   ]
}

Jak widać, zmienia się ostatni - nie zmieniają się rodzice. Prawdopodobnie błąd wynika z tego, że do wywołania rekurencyjnego w funkcji zostaje przekazany "stary obiekt" który nie ma jeszcze zupdate'owanego pola expanded więc url się nie zgadza oraz żaden leaf nie ma expanded === true. Czy jest jakaś opcja, żeby przy generowaniu nowego Node od razu zupdate'ować odpowiednie Node? Jeśli tak, to potrzebowałbym tutaj pomocy z tym. Z góry dzięki :D

0
expand(node: Node, url: string): boolean {
    if (url === node.url) {
       node.expanded = true
       return true
   }

   for(n in node.nodes) { // w tej pętli robisz wszystkie kopie dzieci nie chce mi sie implementować kopii
      toExpand = expand(n, url)

      if (toExpand !== null) {
         n.expanded = true
         return [n].concat(toExpand)
      }
   }

  return false
}

expand(parent, 'someUrl')

Albo nie rozumiem o co chodzi

0

Trochę zmieniłem podejście. Problem jaki miałem był taki, że chciałem jednocześnie tworzyć w pętli deepcoppy oraz aktualizować na podstawie nowej kopii expanded.

W takiej sytuacji jeżeli przekazywałem Nodes[] jako argument do funkcji rekurencyjnej, nie były one odpowiednio zaktualizowane. Rozwiązałem to w trochę inny sposób, ze najpierw stworzyłem deepcoppy głównego obiektu i jego już mutowałem. Jednakże wykorzystując to w ten sposób w komponencie, komponent zachowywał się inaczej niż chciałem więc porzuciłem klonowanie i mutuję stary obiekt (to umiem bo to proste jest :D ). Dzięki wielkie za pomoc.

1 użytkowników online, w tym zalogowanych: 0, gości: 1