使用 React.js 将平面地图转换为嵌套数据结构的最佳方式?

Optimal way of transforming flat map to nested data structure using React.js?

我一直在思考在我的应用程序中处理分组的最佳方式。这是一个视频编辑应用程序,我正在介绍对图层进行分组的功能。如果您熟悉 Figma 或任何 design/video 编辑程序,那么通常可以对图层进行分组。

为了在应用程序中保持简单,视频数据是一张地图

const map = {
  "123": {
    uid: "123",
    top: 25,
    type: "text"
  },
  "345": {
    uid: "345",
    top: 5,
    type: "image"
  },
  "567": {
    uid: "567",
    top: 25,
    type: "group"
    children: ["345", "123"]
  }
}

然后我将它们分组在一个渲染函数中(这感觉很昂贵)

const SomeComponent = () => {
  const objects = useMemo(() => makeTrackObjects(map), [map]);

  return (
    <div>
      {objects.map(object => {
        return <div>Some layer that will change the data causing re-renders</div>
      })}
    </div>
  )
}

这是进行分组的函数

const makeTrackObjects = (map) => {
  // converts map to array
  const objects = Object.keys(map).map((key: string) => ({ ...map[key] }));

  // flat array of all objects to be grouped by their key/id
  const objectsInGroup = objects
    .filter((object) => object.type === "group")
    .map((object) => object.children)
    .flat();

  // filter out objects that are nested/grouped
  const filtered = objects.filter((object) => !objectsInGroup.includes(object.uid))

  // insert objects as children during render
  const grouped = filtered.map((object) => {
      const children = object.children
        ? {
            children: object.children
              .map((o, i) => {
                return {
                  ...map[o]
                };
              })
              .flat()
          }
        : {};

      return {
        ...object,
        ...children
      };
    });

  // the core data is flat but now nested for the UI. Is this inefficient?
  return grouped

}

理想情况下,我希望保持数据平坦,我有很多代码需要更新才能深入数据。把它放平感觉很好,在某些需要的地方有变形金刚。

主要问题是这是否有意义,是否有效,如果不是,那为什么?

如果您 运行 遇到性能问题,您可能想要调查的一个领域是如何链接数组函数(mapfilterflat、 ETC)。每次调用这些函数之一都会根据它接收到的数组创建一个中间集合。 (例如,如果我们链接了 2 个 map 函数,这将遍历整个数组两次)。您可以通过创建一个循环并将项目添加到集合中来提高性能。 (这里有一个 article 涉及到这是换能器的动机。)

我以前没有遇到过性能问题,但您可能还想在不需要时删除传播 (...)。

以下是我对 makeTrackObjects 所做调整的看法。

更新

我还注意到您在遍历数组时使用了 include。这实际上是 O(n^2) 时间复杂度,因为每个项目都将针对整个数组进行扫描。一种缓解方法是改为使用 Set 检查该内容是否已经存在,将其转化为 O(n) 时间复杂度。

const map = {
  "123": {
    uid: "123",
    top: 25,
    type: "text"
  },
  "345": {
    uid: "345",
    top: 5,
    type: "image"
  },
  "567": {
    uid: "567",
    top: 25,
    type: "group",
    children: ["345", "123"]
  }
};

const makeTrackObjects = (map) => {
  // converts map to array
  const objects = Object.keys(map).map((key) => map[key]);

  // set of all objects to be grouped by their key/id
  const objectsInGroup = new Set();
  objects.forEach(object => {
    if (object.type === "group") {
      object.children.forEach(child => objectsInGroup.add(child));
    }
  });

  // filter out objects that are nested/grouped
  const filtered = objects.filter((object) => !objectsInGroup.has(object.uid))

  // insert objects as children during render
  const grouped = filtered.map((object) => {
    const children = {};

    if (object.children) {
      children.children = object.children.map(child => map[child]);
    }

    return {
      ...object,
      ...children
    };
  });

  // the core data is flat but now nested for the UI. Is this inefficient?
  return grouped

}

console.log(makeTrackObjects(map));