Разбор данных в отображаемый вложенный список | реагировать - PullRequest
1 голос
/ 17 февраля 2020

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

Я получаю комментарии из своей базы данных, и структура выглядит следующим образом:

"comments": [
        {
          "id": 5,
          "content": "First comment",
          "path": [
            5
          ],
          "depth": 1
        },
        {
          "id": 6,
          "content": "First reply on first comment",
          "path": [
            5,
            6
          ],
          "depth": 2
        },
        {
          "id": 7,
          "content": "Second comment",
          "path": [
            7
          ],
          "depth": 1
        },
        {
          "id": 8,
          "content": "First reply on second comment",
          "path": [
            7,
            8
          ],
          "depth": 2
        },
        {
          "id": 9,
          "content": "Second reply on second comment",
          "path": [
            7,
            9
          ],
          "depth": 2
        },
        {
          "id": 10,
          "content": "First reply on second comment second reply",
          "path": [
            7,
            9,
            10
          ],
          "depth": 3
        }
      ]

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

comments: [
    {
        id: 5,
        content: "First comment",
        replies: [
            {
                id: 6,
                content: "First reply on first comment",
                depth: 2                               
            }
        ]
    },
    {
        id: 100,
        content: "Comment with no replies",
        replies: []
    }

]

Любая помощь по началу работы с этим очень ценится, и я надеюсь, что я четко описал свою проблему.

Спасибо за чтение и хорошего дня.

1 Ответ

0 голосов
/ 18 февраля 2020

Первое, что я хотел бы сделать, это добавить parentId, children и order к каждому элементу. Это позволит вам перемещаться по дереву вверх или вниз независимо от того, с какого узла вы начинаете, и для обеспечения правильного порядка. parentId не требует пояснений, в то время как children, вероятно, следует назвать childrenIds, поскольку он просто содержит идентификаторы дочерних элементов в соответствующем порядке.

Затем я обычно люблю преобразовывать массив на карту, которая имеет какое-то уникальное значение, например идентификатор. Это дает вам операцию O (1), чтобы добраться до любого узла, который может быть отредактирован или удален. Мне нравится использовать Ramda для подобных вещей, но вы можете использовать любую другую утилиту или написать свою собственную.

utils. js

/**
 * Convert an array to an object, using the `id` as the key.
 */
 const keyById = R.indexBy(R.prop("id"));

Теперь вам нужно найти комментарии, которые находятся вверху списка или под тем, что было бы "root", если бы у вас было один. Поскольку я решил использовать parentId: null для обозначения этого, мы можем найти эти элементы верхнего уровня с помощью этого.

const getTopLevelParents = R.filter(x => !x.parentId);

С этим мы можем легко получить наши элементы верхнего уровня, чтобы начать итерацию , Это где это может быть немного сложнее. Я также использую Ramda здесь, поэтому я надеюсь, что это не слишком необычно для понимания. Суть в том, что, начиная с первого элемента в элементах topLevel, мы рекурсивно находим дочерние элементы, сортируем по «порядку», устанавливаем глубину и объединяем этот массив элементов в один массив. В результате получается нечто более линейное и правильно упорядоченное. Потому что, когда мы go сопоставляем эти данные с компонентами, нам не нужно пропускать, чтобы найти родителей и детей. Мы хотим быть в состоянии go сверху вниз, уже все это выяснили.

/**
 * Converts the mapping to an array and reorders the children so they are directly adjacent with the depth set.
 * @param treeMap Key value pair where the key is the ID and the value is the chapter
 */
function getTreeMapAsList(treeMap) {
  const topLevel = R.compose(
    getTopLevelParents,
    R.values
  )(treeMap);

  /**
   * Nest this function so it can have access to treeMap.
   */
  function getTree(data, depth = 0) {
    return R.reduce(
      (result, curr) => {
        result.push(curr);
        // hasLength is a utility that just checks if the length of an     
        // item is greater than 0 in a way that won't blow up if something
        // doesn't exist.  
        if (hasLength(R.prop("children", curr))) {
          const children = R.compose(
            R.sortBy(R.prop("order")),
            R.reduce((result, id) => {
              const child = R.prop(id, treeMap);
              if (child) {
                return R.compose(
                  R.append(R.__, result),
                  R.assoc("depth", depth + 1)
                )(child);
              }
              return result;
            }, [])
          )(curr.children);

          return result.concat(getTree(children, depth + 1));
        }
        return result;
      },
      [],
      data
    );
  }

Дерево теперь правильно упорядочено, с соответствующей глубиной и сплющено в массив. Наконец, вы можете отобразить этот массив с помощью компонента комментариев.

Комментарий. js

function Comment({ data }) {
  return (
    <div
      style={{
        //It's important to default to zero here. You could also
        // just do this in the data or the mapper originally.
        marginLeft: `${R.propOr(0, "depth", data)}rem`
      }}
    >
      {data.content}
    </div>
  );
}

Приложение. js

function App() {
  // This is the map and should be stored in state somewhere.
  // If it's changing a lot, you should memoize it.
  const treeMap = keyById(data.comments);

  // This is the array, that is now ordered with appropriate depths
  // This should also be memoized.
  const treeList = getTreeMapAsList(treeMap);

  return (
    <div>
      <div>
        {/* Now we just have an array to iterate over. */}
        {treeList.map(item => {
          return <Comment data={item} key={item.id} />;
        })}
      </div>
    </div>
  );
}

Вот рабочий пример . Удачи!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...