reactjs - useCallback/useMemo 与数组
问题描述
我的应用程序内部的性能存在问题。原因是我使用 useCallback 和很多 deps,如下所示
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 个元素,但整个函数会重新运行并返回一个全新的对象,这会在其他地方触发我的渲染函数。
因此,我的问题是:有没有办法让我使用useCallback
或useMemo
优化这段代码?
解决方案
我认为你的性能问题的根本原因是你安装了太多的 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
};
树.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
}
我希望这有帮助。
推荐阅读
- java - 如何在 Spring Boot 中使用一个代码库维护多客户端自定义更改?
- python - PySpark:TypeError:“str”对象在数据帧操作中不可调用
- regex - apache 条件正则表达式无法匹配
- pkcs#11 - 如果派生密钥 CKA_DERIVE=0,C_DeriveKey 的正确错误代码是什么
- angular - 使用@ionic-native/clipboard 检查剪贴板内容是否为空
- android - SNS Mobile 推送通知非常混乱
- android - Kotlin 中未解决的引用
- postgresql - 对固定值使用 WHERE 的查询性能很差。为什么是这样?
- bash - 如何将逗号分隔值拆分为多行?
- node.js - 在其他脚本中包含模型