优化一个自定义hook

62 阅读1分钟

原来的实现

import { SelectProps } from 'antd';
import { useState } from 'react';
import { ShardingComponentEnum } from '~/api-mongodbx/group/index.enum';
import { IChosenServers } from '../index.type';

export const useAliasOption = () => {
  const [aliasOptions, setAliasOptions] = useState<SelectProps['options']>([]);
  const generateAliasOptions = (
    chosenServers?: IChosenServers,
    shardComponent?: ShardingComponentEnum,
    shardId?: string
  ) => {
    if (chosenServers?.servers) {
      const optionsTemp = chosenServers.servers.map((item) => {
        return {
          label: item.alias,
          value: item.alias
        };
      });
      setAliasOptions(optionsTemp);
    } else if (chosenServers?.configServer) {
      let optionsTemp: SelectProps['options'] = [];
      switch (shardComponent) {
        case ShardingComponentEnum['config-servers']:
          optionsTemp = chosenServers.configServer.map((item) => {
            return {
              label: item.alias,
              value: item.alias
            };
          });
          break;
        case ShardingComponentEnum.mongos:
          optionsTemp = chosenServers.mongos?.map((item) => {
            return {
              label: item.alias,
              value: item.alias
            };
          });
          break;
        case ShardingComponentEnum.shards:
          optionsTemp = chosenServers.shards?.[shardId ?? '']?.map((item) => {
            return {
              label: item.alias,
              value: item.alias
            };
          });
          break;
      }
      setAliasOptions(optionsTemp || []);
    }
  };
  return {
    aliasOptions,
    setAliasOptions,
    generateAliasOptions
  };
};

存在的问题

  1. chosenServers对象结构复杂,并且各属性(items)较多,那么每次调用generateAliasOptions时遍历会非常耗费性能
export interface IChosenServers {
  servers?: IChosenServerItem[];
  configServer?: IChosenServerItem[];
  mongos?: IChosenServerItem[];
  shards?: {
    [key: string]: IChosenServerItem[];
  };
}
export interface IChosenServerItem {
  alias: string;
  ip: string;
  port: number;
  cell_id: string;
  server_id: string;
}
  1. 分支太多,且同时使用了if 和switch,代码可读性不强

如何优化

将主机映射为option

通过观察源码,可以发现其实从主机到源码的过程基本都是遍历servers,然后将其转换为SelectProps['options],所以可以将其封装成一个函数

  const mapServersToOptions = (servers?: IChosenServerItem[]) => {
    return (
      servers?.map((item) => ({
        label: item.alias,
        value: item.alias
      })) ?? []
    );
  };

重构switch-case语句

将switch语句提取为独立的函数或使用对象映射的方式来简化代码,增强代码的可读性和易维护性

  const { configServer, mongos, shards } = chosenServers as IChosenServers;
  const serversMap = {
    [ShardingComponentEnum['config-servers']]: () => configServer,
    [ShardingComponentEnum.mongos]: () => mongos,
    [ShardingComponentEnum.shards]: () => shards?.[shardId ?? '']
  };
  const serversGetter = serversMap[shardComponent as ShardingComponentEnum];
  if (serversGetter) {
    const servers = serversGetter();
    if (servers) {
      options = mapServersToOptions(servers);
    }
  }

修改后完整源码

import { SelectProps } from 'antd';
import { useState } from 'react';
import { ShardingComponentEnum } from '~/api-mongodbx/group/index.enum';
import { IChosenServerItem, IChosenServers } from '../index.type';

export const useAliasOption = () => {
  const [aliasOptions, setAliasOptions] = useState<SelectProps['options']>([]);
  const mapServersToOptions = (servers?: IChosenServerItem[]) => {
    return (
      servers?.map((item) => ({
        label: item.alias,
        value: item.alias
      })) ?? []
    );
  };
  const generateAliasOptions = (
    chosenServers?: IChosenServers,
    shardComponent?: ShardingComponentEnum,
    shardId?: string
  ) => {
    let options;
    if (chosenServers?.servers) {
      options = mapServersToOptions(chosenServers.servers);
    } else if (
      chosenServers?.configServer &&
      chosenServers.mongos &&
      chosenServers.shards
    ) {
      const { configServer, mongos, shards } = chosenServers as IChosenServers;
      const serversMap = {
        [ShardingComponentEnum['config-servers']]: () => configServer,
        [ShardingComponentEnum.mongos]: () => mongos,
        [ShardingComponentEnum.shards]: () => shards?.[shardId ?? '']
      };
      const serversGetter = serversMap[shardComponent as ShardingComponentEnum];
      if (serversGetter) {
        const servers = serversGetter();
        if (servers) {
          options = mapServersToOptions(servers);
        }
      }
    }
    setAliasOptions(options || []);
  };
  return {
    aliasOptions,
    setAliasOptions,
    generateAliasOptions
  };
};