React 条件 class 的几种写法对比
FreeGuideOnline
最新
2026-07-05
jsx
function Component({ isActive, isDisabled }) {
return (
<div className={card ${isActive ? 'active' : ''} ${isDisabled ? 'disabled' : ''}}>
内容
);
}
优点:
- 零依赖,原生语法
- 适合极简场景
缺点:
- 会产生多余空格,需要手动处理 `undefined` 或 `false` 带来的冗余空白(React 会自动忽略 `false` / `null` / `undefined` 值,但对空格处理不完美)
- 条件复杂时,可读性急剧下降,括号嵌套难以维护
- 类名顺序无规律,不易阅读
### 二、数组 + join 方法
将每个类名视为数组元素,过滤掉假值后拼接。
```jsx
function Component({ isActive, isDisabled }) {
const classes = [
'card',
isActive && 'active',
isDisabled && 'disabled'
].filter(Boolean).join(' ');
return <div className={classes}>内容</div>;
}
优点:
- 避免了多余空格
- 可读性稍好,逻辑清晰
- 可以用变量提取,方便复用
缺点:
- 仍然需要手动过滤
false等值 - 冗长,每次都要写
filter(Boolean).join(' ') - 动态条件与静态类名混在一起,对比度不高
三、classnames 库
最流行的解决方案,npm 周下载量过千万,已成为事实标准。
安装:
npm install classnames
使用:
import classNames from 'classnames';
function Component({ isActive, isDisabled }) {
return (
<div className={classNames('card', {
active: isActive,
disabled: isDisabled
})}>
内容
</div>
);
}
也可以混合字符串和条件:
classNames('btn', isPrimary && 'btn-primary', size && `btn-${size}`)
优点:
- 语法简洁,对象键值对直观映射状态与类名
- 自动忽略
false、null、undefined等值,不会产生多余空格 - 支持多种参数形式(字符串、对象、数组)
- 生态成熟,几乎所有 React 项目都在用
缺点:
- 引入了一个额外依赖(但体积极小,约 800 字节)
四、clsx 库
clsx 是比 classnames 更轻量、性能更优的替代品,API 基本兼容。
安装:
npm install clsx
使用:
import clsx from 'clsx';
function Component({ isActive, isDisabled }) {
return (
<div className={clsx('card', {
active: isActive,
disabled: isDisabled
})}>
内容
</div>
);
}
优点:
- 比
classnames更快(基准测试显示约 2-3 倍优势) - 体积更小(228B gzipped)
- API 几乎相同,切换成本极低
- 支持条件对象、数组和嵌套参数
缺点:
- 社区流行度稍低于
classnames,但趋势上涨 - 同样需要额外依赖
五、CSS Modules 的条件组合
如果项目使用 CSS Modules,可以结合上述工具处理条件样式。
import styles from './Component.module.css';
import clsx from 'clsx';
function Component({ isActive, isDisabled }) {
return (
<div className={clsx(styles.card, {
[styles.active]: isActive,
[styles.disabled]: isDisabled
})}>
内容
</div>
);
}
优点:
- 与模块化样式天然结合,避免全局污染
- 动态类名依然清晰
缺点:
- 写法略长,需用计算属性名
- 如果类名较多,对象结构可能显得重复
六、自定义 Hook 封装(进阶)
当项目中有大量重复的条件组合,可以封装一个 useClassName 钩子。
function useClassName(base, conditions) {
return clsx(base, conditions);
}
function Component(props) {
const className = useClassName('card', {
active: props.isActive,
disabled: props.isDisabled
});
return <div className={className}>内容</div>;
}