Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/drupal/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 将数据解析为可映射嵌套列表| React_Javascript_Reactjs_Algorithm_Sorting - Fatal编程技术网

Javascript 将数据解析为可映射嵌套列表| React

Javascript 将数据解析为可映射嵌套列表| React,javascript,reactjs,algorithm,sorting,Javascript,Reactjs,Algorithm,Sorting,我正在建立一个数据库,您可以在其中添加对会议的评论和对这些会议的回复。我从中获得灵感,因为我以前从未做过这样的事情 我正在从数据库中获取我的评论,结构如下所示: "comments": [ { "id": 5, "content": "First comment", "path": [ 5

我正在建立一个数据库,您可以在其中添加对会议的评论和对这些会议的回复。我从中获得灵感,因为我以前从未做过这样的事情

我正在从数据库中获取我的评论,结构如下所示:

"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: []
    }

]
非常感谢您对如何开始这方面的任何帮助,我希望我已经清楚地描述了我的问题


感谢阅读,祝您度过愉快的一天。

我要做的第一件事是在每个项目中添加
parentId
children
order
。这将允许您上下遍历树,无论从哪个节点开始,并确保正确的顺序。
parentId
是不言自明的,而
childrenid
可能应该命名为
childrenIds,因为它只是按照适当的顺序保存子项的id

然后,我通常喜欢将数组转换为一个映射,该映射由一个唯一的值(如ID)进行键控。这将为您提供一个O(1)操作,以访问任何可能被编辑或删除的节点。我喜欢使用Ramda来处理类似的事情,但您可以使用任何其他实用程序或编写自己的实用程序

utils.js 现在,您需要找到列表顶部的注释,或者如果您有注释,则位于“根”下方。因为我选择了使用
parentId:null
来表示这一点,所以我们可以找到这些顶级项

const getTopLevelParents = R.filter(x => !x.parentId);
有了这一点,我们可以很容易地让顶级项目开始迭代。这可能会变得更复杂一些。我在这里也使用Ramda,所以我希望它不会太不寻常。要点是,从顶级项中的第一项开始,我们递归地查找子项,按“顺序”排序,设置深度,并将该项数组连接到单个数组。因此,结果是更线性和更有序的。因为当我们将这些数据映射到组件时,我们不想为了找到父对象和子对象而跳过。我们希望能够从上到下,已经解决了所有这些问题

/**
 * 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
    );
  }
现在,该树已正确排序,具有适当的深度,并已展平为一个数组。最后,您可以使用注释组件映射此数组

Comment.js
函数注释({data}){
返回(
{
返回;
})}
);
}

。祝你好运

我要做的第一件事是在每个项目中添加
parentId
children
order
。这将允许您上下遍历树,无论从哪个节点开始,并确保正确的顺序。
parentId
是不言自明的,而
childrenid
可能应该命名为
childrenIds,因为它只是按照适当的顺序保存子项的id

然后,我通常喜欢将数组转换为一个映射,该映射由一个唯一的值(如ID)进行键控。这将为您提供一个O(1)操作,以访问任何可能被编辑或删除的节点。我喜欢使用Ramda来处理类似的事情,但您可以使用任何其他实用程序或编写自己的实用程序

utils.js 现在,您需要找到列表顶部的注释,或者如果您有注释,则位于“根”下方。因为我选择了使用
parentId:null
来表示这一点,所以我们可以找到这些顶级项

const getTopLevelParents = R.filter(x => !x.parentId);
有了这一点,我们可以很容易地让顶级项目开始迭代。这可能会变得更复杂一些。我在这里也使用Ramda,所以我希望它不会太不寻常。要点是,从顶级项中的第一项开始,我们递归地查找子项,按“顺序”排序,设置深度,并将该项数组连接到单个数组。因此,结果是更线性和更有序的。因为当我们将这些数据映射到组件时,我们不想为了找到父对象和子对象而跳过。我们希望能够从上到下,已经解决了所有这些问题

/**
 * 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
    );
  }
现在,该树已正确排序,具有适当的深度,并已展平为一个数组。最后,您可以使用注释组件映射此数组

Comment.js
函数注释({data}){
返回(
{
返回;
})}
);
}

。祝你好运

我以前实现过类似的东西,但我选择将数据转换成一个由ID设置关键帧的映射/对象。我会添加一个不会被渲染的“根”,并将该对象转换为平面阵列,更类似于第一个对象的外观。然后,使用深度道具,设置边距,使其在其父项下缩进一个设置量。对我来说,这只是另一个ID,但也可能是你在那里的路径。然后是一个深度优先的树渲染算法。谢谢@jktravis的评论。我从未听说过深度优先算法,所以我不太确定如何在我的案例中实现它。也许它超级简单,但事实上,我以前从未使用过它,这让它成为嘲弄。你介意帮我一点忙吗?这听起来确实很复杂,但它实际上只是一个用于搜索或遍历树的递归算法。这才是你真正要做的。看见不过,在这里,您基本上是将数据转换为react组件。如果可以的话,我会给每一个添加一个
parentId
和一个
children
道具。举个例子会不会太过分?我昨天尽了最大的努力,但还是没能成功你是不是碰巧成功了@MartinNordströmI以前实现过类似的东西,但我选择将数据转换成一个由ID设置关键帧的映射/对象。我
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>
  );
}