首页 > 解决方案 > 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 个元素,但整个函数会重新运行并返回一个全新的对象,这会在其他地方触发我的渲染函数。

因此,我的问题是:有没有办法让我使用useCallbackuseMemo优化这段代码?

标签: reactjsreact-hooks

解决方案


我认为你的性能问题的根本原因是你安装了太多的 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
}


我希望这有帮助。


推荐阅读