我使用React + d3js在svg上呈现数据,我有一个包含如下数据的大数组
const arrayItemExample = {
id: 1,
text: 'Some Text for node',
x: 100,
y: 300,
selected: false,
dragging: false
}这类元素的清单可达数万份。主要问题是,当我单击或拖动呈现的元素时,会更新该元素上的数据:
const handleDragStart = useCallback((id)=>{
setData(data=>{
return data.map(item=>{
if(item.id === id){
return {
...item,
dragging: true
}
}
return item
})
})
},[])
const handleSelect = useCallback((id)=>{
setData(data=>{
return data.map(item=>{
if(item.id === id){
return {
...item,
selected: true
}
}
return item
})
})
},[])这两个函数都能很好地处理少量的数据,但是如果页面上有100个或更多的元素,那么单击或拖动元素会在元素重绘过程中减缓页面的速度。
是否有任何方法通过重绘其唯一的元素来更新特定元素中的数据?我不能使用组件的内部状态,因为我需要所选和可拖动元素的总数据:例如,我用ctrl选择了几个元素,当我开始拖动其中一个时,另一个也必须被拖动。
发布于 2022-12-02 21:47:55
D3数据集最常使用SVG呈现,这是一种保留模式的图形模型,易于使用,但性能有限。SVG图表通常可以处理大约1000个数据点。
自从D3 v4之后,您还可以选择使用canvas来呈现图表,这是一个即时模式的图形模型。使用画布,您可以预期呈现大约10,000个数据点,同时保持平滑的60 you交互。
所以我的建议是使用画布而不是SVG。如果您有时间,我建议您改用WebGL。
发布于 2022-12-02 23:40:54
要更新数组中特定元素的数据而不重新绘制所有元素,可以结合使用useReducer钩子和useMemo钩子。useReducer钩子允许您定义一个还原器函数,它根据分派的操作更新状态。useMemo钩子允许您计算一个回忆录值,该值只有在某个依赖项发生变化时才会重新计算。
下面是一个示例,说明如何使用useReducer和useMemo挂钩来更新数组中特定元素的数据,而不必重新绘制所有元素:
const [state, dispatch] = useReducer(reducer, initialState);
const data = useMemo(() => {
return state.data.map(item => {
if (item.id === state.selectedId) {
return {
...item,
selected: true
};
} else if (item.id === state.draggingId) {
return {
...item,
dragging: true
};
}
return item;
});
}, [state.data, state.selectedId, state.draggingId]);
const handleDragStart = useCallback((id) => {
dispatch({ type: 'DRAG_START', id });
}, []);
const handleSelect = useCallback((id) => {
dispatch({ type: 'SELECT', id });
}, []);在上面的代码中,我们使用useReducer钩子定义了一个还原器函数。还原器函数接受当前状态和动作,并根据动作返回一个新状态。我们还定义了两个动作创建者,handleDragStart和handleSelect,它们分别分派DRAG_START和选择操作。
接下来,我们使用useMemo钩子来计算数据数组的回传版本。useMemo钩子接受返回要回传的值的函数和依赖项列表。在这种情况下,函数返回更新后的数据数组,并根据当前状态的selectedId和draggingId更新选定的和拖动的元素。
最后,我们使用React组件中的数据数组来呈现元素。由于数据数组是回忆录的,所以只有当状态中的selectedId或draggingId发生变化时,才会重新计算它,这将确保
发布于 2022-12-03 07:10:34
有几种方法可以优化数据的呈现以提高性能。
您可以采取的一种方法是在您的React组件中使用shouldComponentUpdate生命周期方法。此方法允许您控制组件何时更新,这有助于防止不必要的重新呈现。例如,您可以使用shouldComponentUpdate只在组件的选定或拖动支柱发生更改时重新呈现组件,而不是每次更新父组件的数据数组时重新呈现。
另一种方法是使用虚拟列表组件,例如react虚拟化库。虚拟化列表只呈现当前在屏幕上可见的元素,这可以显着地提高呈现大型数据列表的性能。
此外,优化d3.js代码以避免不必要的重呈现元素通常是一个好主意。例如,您可以使用.exit()和.enter()选择在d3中只更新从数据中添加或删除的元素,而不是每次数据更改时重新呈现整个元素列表。
要在React组件中使用shouldComponentUpdate方法,可以将该方法添加到组件类中,如下所示:
class MyComponent extends React.Component {
shouldComponentUpdate(nextProps) {
// Only update the component if the selected or dragging prop has changed
return this.props.selected !== nextProps.selected || this.props.dragging !== nextProps.dragging;
}
render() {
// Render the component
}
}要使用react虚拟化库,可以从npm安装它,然后在代码中使用VirtualizedList组件,如下所示:
import { VirtualizedList } from 'react-virtualized';
const MyList = ({ data }) => {
return (
<VirtualizedList
data={data}
// Specify the height and width of the list
height={300}
width={300}
// Specify a function to render each item in the list
renderItem={({ item, index }) => {
return <MyComponent key={item.id} item={item} />;
}}
/>
);
};下面是使用.exit()和.enter()选项在d3中只更新从数据中添加或删除的元素的示例,而不是每次数据更改时重新呈现整个元素列表:
// Select all elements with the specified class
const elements = d3.selectAll('.my-element-class');
// Bind the data to the selection
const updatedElements = elements.data(myData);
// Remove any elements that are no longer in the data
updatedElements.exit().remove();
// Add new elements for any data that doesn't have a corresponding element
const newElements = updatedElements.enter().append('div')
.classed('my-element-class', true)
// Set the initial attributes of the new elements
.attr('x', d => d.x)
.attr('y', d => d.y)
.text(d => d.text);
// Update the attributes of all elements, whether they are new or not
updatedElements.merge(newElements)
.attr('x', d => d.x)
.attr('y', d => d.y)
.text(d => d.text);此代码将使用类选择所有元素,将指定的数据绑定到所选内容,删除数据中不再包含的任何元素,为没有相应元素的任何数据添加新元素,并更新所有元素的属性,无论它们是否是新元素。这允许您只更新已更改的元素,而不是每次数据更改时重新呈现整个元素列表。
https://stackoverflow.com/questions/74633288
复制相似问题