我的应用程序内部性能出现问题。原因是我将useCallback与很多dep一起使用,如下所示
const getTreeData = React.useCallback((tree: Area.Model[]): TreeItem[] => {
let treeData: TreeItem[] = [];
if (tree) {
treeData = {
flatData: tree.map(
(area): any => {
const areaKey = getKeyForArea(area.id, area.type, area.closestGroupId);
return {
id: area.id,
name: area.name,
type: area.type,
title: (
<TreeTitle
id={area.id}
key={area.id}
type={area.type}
title={area.name}
closestGroupId={area.closestGroupId}
expandable={area.drillableDirections !== undefined && area.drillableDirections.includes(Drill.Direction.DOWN)}
status={status[areaKey]}
counter={subAreas[areaKey]}
unselectedStoreCounter={unselectedStoreCounter[areaKey]}
onAggregationButtonClick={handleAggregateOptionToggle}
onQuickAggregationOptionForSubGroups={handleQuickAggregateOptionForSubGroupsToggle}
onQuickAggregationOptionForSubStores={handleQuickAggregateOptionForSubStoresToggle}
/>
),
parent: area.closestGroupId,
expanded: status[areaKey].isExpanded,
};
},
),
getKey: (node: any): number => node.id,
getParentKey: (node: any): number => node.parent || 0,
rootKey: 0,
};
}
return treeData;
}, [status, subAreas, unselectedStoreCounter, handleAggregateOptionToggle, handleQuickAggregateOptionForSubGroupsToggle, handleQuickAggregateOptionForSubStoresToggle]);
如您所见,所有依赖项都在代码中使用。但是,每次进行更改时,只会更新1个元素,但是整个函数将重新运行并返回一个全新的对象,这将在另一个地方触发我的render函数。
因此,我的问题是:我是否可以使用useCallback
或useMemo
来优化此代码?
答案 0 :(得分:1)
我认为造成性能问题的根本原因是您安装了过多的dom元素。我对此有相同的问题,并通过虚拟化树来解决。我为此使用了react-virtualized-tree,这就是它的运行方式。
VirtualizedTree.js
import React from 'react';
import PropTypes from 'prop-types';
import Tree from 'react-virtualized-tree/lib/Tree';
import TreeStateModifiers from 'react-virtualized-tree/lib/state/TreeStateModifiers'
import { UPDATE_TYPE } from 'react-virtualized-tree/lib/contants'
import { Node } from 'react-virtualized-tree/lib/shapes/nodeShapes';
export default class UnstableFastTree extends React.Component {
static contextTypes = {
unfilteredNodes: PropTypes.arrayOf(PropTypes.shape(Node))
};
get nodes() {
return this.context.unfilteredNodes || this.props.nodes;
}
handleChange = ({ node, type, index }) => {
let nodes;
if (type === UPDATE_TYPE.UPDATE) {
nodes = TreeStateModifiers.editNodeAt(this.props.nodes, index, node);
} else {
nodes = TreeStateModifiers.deleteNodeAt(this.props.nodes, index);
}
this.props.onChange(nodes);
};
render() {
return (
<Tree
nodeMarginLeft={this.props.nodeMarginLeft}
nodes={this.props.nodes}
onChange={this.handleChange}
NodeRenderer={this.props.children}
/>
);
}
}
UnstableFastTree.propTypes = {
extensions: PropTypes.shape({
updateTypeHandlers: PropTypes.object
}),
nodes: PropTypes.shape({
flattenedTree: PropTypes.arrayOf(PropTypes.arrayOf(PropTypes.oneOf([PropTypes.number, PropTypes.string])))
.isRequired,
tree: PropTypes.arrayOf(PropTypes.shape(Node)).isRequired
}),
onChange: PropTypes.func,
children: PropTypes.func.isRequired,
nodeMarginLeft: PropTypes.number,
width: PropTypes.number,
scrollToId: PropTypes.number
};
UnstableFastTree.defaultProps = {
nodeMarginLeft: 30
};
Tree.js
import React, { useMemo } from 'react'
import PropTypes from 'prop-types'
import pick from 'lodash/pick'
import VirtualizedTree from '@controls/VirtualizedTree'
import TreeState from 'react-virtualized-tree/lib/state/TreeState'
import TreeNode from './TreeNode'
export default function BrowseTree(props) {
const {
treeData
} = props
const getAllNodes = all => all.reduce((acc, el) => [
...acc,
el,
...(el.collapse ? getAllNodes(el.children) : [])
], [])
const nodes = useMemo(() => TreeState.createFromTree(treeData), [treeData])
const treeProps = pick(props, [
'type', 'selectedNodeId', 'onNodeClick', 'onHideDialog', 'onShowDialog',
'browseToggle', 'disableIds', 'config', 'fetching', 'topicIcon', 'role'
])
return (
<VirtualizedTree nodes={nodes}>
{({ style, node }) => (
<TreeNode
key={node.db_id}
style={style}
node={node}
{...treeProps}
/>
)}
</VirtualizedTree>
)
}
BrowseTree.propTypes = {
type: PropTypes.string.isRequired,
treeData: PropTypes.array.isRequired
}
我希望这会有所帮助。