使用 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
}
理想情况下,我希望保持数据平坦,我有很多代码需要更新才能深入数据。把它放平感觉很好,在某些需要的地方有变形金刚。
主要问题是这是否有意义,是否有效,如果不是,那为什么?
如果您 运行 遇到性能问题,您可能想要调查的一个领域是如何链接数组函数(map
、filter
、flat
、 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));
我一直在思考在我的应用程序中处理分组的最佳方式。这是一个视频编辑应用程序,我正在介绍对图层进行分组的功能。如果您熟悉 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
}
理想情况下,我希望保持数据平坦,我有很多代码需要更新才能深入数据。把它放平感觉很好,在某些需要的地方有变形金刚。
主要问题是这是否有意义,是否有效,如果不是,那为什么?
如果您 运行 遇到性能问题,您可能想要调查的一个领域是如何链接数组函数(map
、filter
、flat
、 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));