【业务组件优化】解耦合+映射,改观React业务组件代码例子

572 阅读3分钟

场景

我们有如下的业务场景:

一个很简单的Tag标签,标签有如下分类,每个代表打卡结果,其中迟到、早退、严重迟到为一个颜色,出差为一个颜色,缺卡、迟到旷工为一个颜色,请假为一个颜色;而正常的打卡结果又是只为单独的文字:

2022.04.24_肖国垚&dd959e8753765a54f5ff701c2dfcb145.png

❌差的做法(不推荐):

import React, { Component } from 'react'
import styles from './style.module.less'
import classnames from 'classnames'

/**
 * 考勤结果枚举
 * @type {{}}
 */
const Eum = {
  normal: '正常',
  normal_by_user: '正常(补)',
  normal_by_admin: '正常(调)',
  late: '迟到',
  serious_late: '严重迟到',
  absenteeism: '旷工迟到',
  leave_early: '早退',
  absence: '缺卡',
  ask_for_leave: '请假',
  official_leave: '公出',
  business_trip: '出差'
}

const Tag = ({ text, onlyText = false }) => {

  let same1 = (text === 'late') || (text === 'serious_late') || (text === 'absence')
  let same2 = (text === 'absence') || (text === 'absenteeism')

  const renderSty = same1 ? 'later' : same2 ? 'over' : text

  const show = Eum[text] ? Eum[text] : ''

  const wrapClass = classnames({
    [styles[renderSty]]: !onlyText,
    [styles['wrap_tag']]: !onlyText,
    only_text: onlyText
  })

  return <div className={wrapClass}>{show}</div>

}
export default Tag

使用:

import Tag from '@/component/Tag'

const Test = () => {
    // 一写判断
  return  <Tag text='' onlyText={} />
}

export default Test

上面代码的做法是吧,所有的这个业务写在一个组件里面,但是这有许多不好的地方;

  1. 耦合度太高,比较混乱,太依据业务,会比较难维护。
  2. 在整个应用上,组件不通用。我想在其他地方继续使用Tag,发现它和业务捆绑的太死了难以复用。
  3. 使用上需要有两个判断:后端返回的结果text对应枚举的文字,onlyText是否只展示纯文本。有点冗余

组件解耦合

把组件和业务的关联性变低,解耦合,让组件更通用,更容易维护,接下来我们实操下。

把Tag改为一个通用的组件,只要传入对应的文字就展示对应的文字,可以根据预设的color来生产对应的classname(需要在样式上写好类名即可,如果下次有增加新的直接增加预设样式即可)

改造后如下:

import React, { Component } from 'react'
import styles from './style.module.less'
import classnames from 'classnames'

/**
 * 打卡结果标签
 */
const Tag = ({ text = '', color = '', background = '', style }) => {

  // 预设color集合
  const preSetColorList = ['pink', 'green', 'blue', 'orange']

  const findPreSetColor = (color) => {
    return !!preSetColorList.find(item => item === color)
  }

  const wrapClass = classnames({
    [styles['wrap_tag']]: true,
    [styles[color]]: true,
  })

  const tagStyle = {
    color: color && !findPreSetColor(color) ? color : undefined,
    background: background,
    ...style
  }

  return <div className={wrapClass} style={tagStyle}>{text}</div>
}
export default Tag

不使用antd的tag是因为满足不了需求,UI有偏差,场景不复杂,自己写更快。

使用:

import Tag from '@/component/Tag'
import TagStyleListConfig from './config'

const Test = () => {
  return TagStyleListConfig[text] ? <Tag {...TagStyleListConfig[text]}/> : ''
}

export default Test

写一份业务需要的映射配置,这样做是为了保持业务和组件分离,逻辑更清晰:

//映射枚举对象,用来展示对应需要展示的内容
export const TagStyleListConfig = {
  none: {
    text: '缺卡',
    color: 'pink'
  },
  early: {
    text: '早退',
    color: 'orange'
  },
  later: {
    text: '迟到',
    color: 'orange'
  },
  laterSeri: {
    text: '严重迟到',
    color: 'orange'
  },
  laterNone: {
    text: '旷工迟到',
    color: 'orange'
  },
  leave: {
    text: '请假',
    color: 'green'
  }
}

通过TagStyleListConfig建立一个映射对应内容,这样就不用写多个判断。

并且解决了最初的几个问题:

  1. 解决了高耦合问题,例如直接增加color就可以增加其他场景:
  // 预设color集合
  const preSetColorList = ['pink', 'green', 'blue', 'orange', '增加其他类名和样式']
  1. 通用问题,在其他模块上仍能使用,与业务划分,更容易维护:
<Tag text='测试' color='test'/>

通过以上例子,我们利用了解耦的方法+映射,生产出对应易于组件维护和复用,代码逻辑更清楚。