Массаж JSON ответ, чтобы вписаться в структуру treeData для реагировать-просто-дерево-меню - PullRequest
0 голосов
/ 23 апреля 2020

У меня есть компонент React, который извлекает массив объектов (пар ключ-значение) из REST API через конечную точку HTML:

[
  { 
    "id": 1,
    "grouping1": "first-level-node-1",
    "grouping2": "second-level-node-1",
    "theThing": "third-level-node-1",
    "someData": "data here that is associated with theThing",
    "someUrl": "http://someurl.com"
  },
  {
    "id": 2,
    "grouping1": "first-level-node-2",
    "grouping2": "second-level-node-1",
    "theThing":  "third-level-node-1",
    .
    .
    .
  }
]

Я пытаюсь манипулировать ответом JSON так что он будет отображаться с реагировать-просто-дерево-меню. Чтобы сгенерировать TreeMenu , необходимо предоставить данные в виде массива:

// as an array
const treeData = [
  {
    key: 'first-level-node-1',
    label: 'Node 1 at the first level',
    ..., // any other props you need, e.g. url
    nodes: [
      {
        key: 'second-level-node-1',
        label: 'Node 1 at the second level',
        nodes: [
          {
            key: 'third-level-node-1',
            label: 'Last node of the branch',
            nodes: [] // you can remove the nodes property or leave it as an empty array
          },
        ],
      },
    ],
  },
  {
    key: 'first-level-node-2',
    label: 'Node 2 at the first level',
  },
];

или в виде объекта:

// or as an object
const treeData = {
  'first-level-node-1': {               // key
    label: 'Node 1 at the first level',
    index: 0, // decide the rendering order on the same level
    ...,      // any other props you need, e.g. url
    nodes: {
      'second-level-node-1': {
        label: 'Node 1 at the second level',
        index: 0,
        nodes: {
          'third-level-node-1': {
            label: 'Node 1 at the third level',
            index: 0,
            nodes: {} // you can remove the nodes property or leave it as an empty array
          },
        },
      },
    },
  },
  'first-level-node-2': {
    label: 'Node 2 at the first level',
    index: 1,
  },
};

Я попытался классифицировать JSON ответ на основе group1 (узел первого уровня) и group2 (узел второго уровня), чтобы он «вписался» в treeData:

  const fetchItems = async () => {
    const data = await fetch('http://localhost:3001/stuff');
    const input = await data.json();
    const output = input.reduce((acc, item) => ({
      ...acc,
      [item.grouping1]: {
        ...acc[item.grouping1],
        [item.grouping2]: [
          ...(acc[item.gropuing1] && acc[item.grouping1][item.grouping2] || []),
          item,
        ]
      }
    }), {})

и теперь у меня есть объекты (group1), которые содержат объекты (group2) которые содержат массив пар «ключ-значение».

  first-level-node-1:
    second-level-node-1: Array(4)
      0: {id: 1, grouping1: "first-level-node-1", grouping2: "second-level-node-1", theThing: "third-level-node-1"}
      .
      .
      .
  first-level-node-2:
    second-level-node-1: Array(16)
      0: {id: 2, grouping1: "first-level-node-2", grouping2: "second-level-node-1", theThing: "third-level-node-1"}
      .
      .
      .

Но это не та структура treeData, которую требует реакция-simple-tree-menu. Как мне помассировать ответ JSON, чтобы он соответствовал структуре treeData?

Вот отличная запись о том, как настроить боковое меню и запустить его в React, но ничего, что показывает как получить типичный JSON ответ для вписывания в требуемую структуру.

Обновление:

Ниже приведены данные TreeMenu , которые управляют этой реакцией. Компонент меню простого дерева

<TreeMenu
  data={[
    {
      key: 'mammal',
      label: 'Mammal',
      nodes: [
        {
          key: 'canidae',
          label: 'Canidae',
          nodes: [
            {
              key: 'dog',
              label: 'Dog',
              nodes: [],
              url: 'https://www.google.com/search?q=dog'
            },
            {
              key: 'fox',
              label: 'Fox',
              nodes: [],
              url: 'https://www.google.com/search?q=fox'
            },
            {
              key: 'wolf',
              label: 'Wolf',
              nodes: [],
              url: 'https://www.google.com/search?q=wolf'
            }
          ],
          url: 'https://www.google.com/search?q=canidae'
        }
      ],
      url: 'https://www.google.com/search?q=mammal'
    },
    {
      key: 'reptile',
      label: 'Reptile',
      nodes: [
        {
          key: 'squamata',
          label: 'Squamata',
          nodes: [
            {
              key: 'lizard',
              label: 'Lizard',
              url: 'https://www.google.com/search?q=lizard'
            },
            {
              key: 'snake',
              label: 'Snake',
              url: 'https://www.google.com/search?q=snake'
            },
            {
              key: 'gekko',
              label: 'Gekko',
              url: 'https://www.google.com/search?q=gekko'
            }
          ],
          url: 'https://www.google.com/search?q=squamata'
        }
      ],
      url: 'https://www.google.com/search?q=reptile'
    }
  ]}
  debounceTime={125}
  disableKeyboard={false}
  hasSearch
  onClickItem={function noRefCheck(){}}
  resetOpenNodesOnDataUpdate={false}
/>

Если я правильно понимаю, Млекопитающее - это первый уровень-узел-1, а Рептилия - первый-уровень-узел-2. Canidae и Squamata являются узлами второго уровня-1 под соответствующими узлами первого уровня. Dog, Fox и Wolf - это третий уровень-узел-1, узел-2 и узел-3 соответственно. Ящерица, Змея и Гекко также являются третьим уровнем-узлом-1, узлом-2 и узлом-3. Пример, который я использовал в самом начале этого поста, может сбивать с толку. Приношу свои извинения, если это так.

Вот данные JSON, которые больше напоминают то, с чем я работаю:

[
  {
    "id": 2,
    "grouping1": "I124",
    "grouping2": "Cross_Streets",
    "theThing": "12th",
    "url": "http://url2.com"
  },
  {
    "id": 3,
    "grouping1": "I124",
    "grouping2": "Cross_Streets",
    "theThing": "13th",
    "url": "http://url3.com"
  },
  {
    "id": 4,
    "grouping1": "I124",
    "grouping2": "Cross_Streets",
    "theThing": "4th",
    "url": "http://url4.com"
  },
  {
    "id": 14,
    "grouping1": "I124",
    "grouping2": "Ramps",
    "theThing": "Ramp_A",
    "url": "http://url14.com"
  },
  {
    "id": 15,
    "grouping1": "I124",
    "grouping2": "Ramps",
    "theThing": "Ramp_B",
    "url": "http://url15.com"
  },
  {
    "id": 41,
    "grouping1": "I75",
    "grouping2": "Cross_Streets",
    "theThing": "100th",
    "url": "http://url41.com"
  }
]

Цель состоит в том, чтобы сделать выше JSON в меню реагировать-просто-дерево:

+ I124
    + Cross_Streets
        12th
        13th
        4th
    + Ramps
        Ramp_A
        Ramp_B
+ I75
    + Cross_Streets
        4th

1 Ответ

1 голос
/ 23 апреля 2020

Вот возможное решение, которое вы могли бы применить, однако я не уверен, откуда вы получаете labels, но я оставлю это на ваше усмотрение.

Вот пример с object как результат:

const DATA = [
  {
    id: 2,
    grouping1: "I124",
    grouping2: "Cross_Streets",
    theThing: "12th",
    url: "http://url2.com"
  },
  {
    id: 3,
    grouping1: "I124",
    grouping2: "Cross_Streets",
    theThing: "13th",
    url: "http://url3.com"
  },
  {
    id: 4,
    grouping1: "I124",
    grouping2: "Cross_Streets",
    theThing: "4th",
    url: "http://url4.com"
  },
  {
    id: 14,
    grouping1: "I124",
    grouping2: "Ramps",
    theThing: "Ramp_A",
    url: "http://url14.com"
  },
  {
    id: 15,
    grouping1: "I124",
    grouping2: "Ramps",
    theThing: "Ramp_B",
    url: "http://url15.com"
  },
  {
    id: 41,
    grouping1: "I75",
    grouping2: "Cross_Streets",
    theThing: "100th",
    url: "http://url41.com"
  }
];

const resultAsObject = DATA.reduce((accumulator, item) => {
  const groupId = item["grouping1"];
  const subGroupId = item["grouping2"];
  const subGroupItemId = item["theThing"];
  const url = item["url"];

  const group = accumulator[groupId] || {
    key: groupId.toLowerCase(),
    label: groupId,
    nodes: []
  };
  const subGroup = group.nodes.find(
    item => item.key === subGroupId.toLowerCase()
  ) || {
    key: subGroupId.toLowerCase(),
    label: subGroupId,
    nodes: []
  };
  const updatedSubGroupNodes = [
    {
      key: subGroupItemId.toLowerCase(),
      label: subGroupItemId,
      url: url,
      nodes: []
    }
  ];
  const updatedSubGroup = {
    ...subGroup,
    nodes: updatedSubGroupNodes
  };
  const t1 = [...group.nodes, updatedSubGroup].reduce((acc, i) => {
    const category = acc.find(t => t.key === i.key) || {
      key: i.key,
      label: i.label,
      nodes: []
    };
    const updatedNodes = [...category.nodes, ...i.nodes];
    const updatedCategory = { ...category, nodes: updatedNodes };

    // replace the existing category object and append
    // the updated object with populated `nodes` property
    return [...acc.filter(t => t.key !== category.key), updatedCategory];
  }, []);

  const updatedGroup = {
    ...group,
    nodes: t1
  };
  return {
    ...accumulator,
    [groupId]: updatedGroup
  };
}, {});

console.log(resultAsObject);
...