直接拼接字符串写BEM类名易出错,因逻辑分散、条件多,易漏空格或误转布尔值为字符串;classnames通过对象键值映射确保仅真值生效,更安全。

为什么直接拼接字符串写 BEM 类名在 React 里容易出错
因为手动拼接 block__element--modifier 时,逻辑分散、条件判断多,一不小心就漏空格、重复加类、或把布尔值转成字符串(比如 className={isActive && 'btn--active'} 在 isActive 为 false 时会变成 "false")。React 的 className 不接受 false/null/undefined,但字符串化后就真成了类名。
classnames 如何安全组合 BEM 结构
classnames 把对象键作为类名,值为真值才生效,天然适配 BEM 的动态修饰符。关键不是“用它”,而是怎么组织结构让它可读、可维护。
- 基础块名固定写死:
btn;元素名用模板拼接:`${block}__icon`;修饰符统一走对象键 - 避免嵌套过深:不要在
classnames()里再调用一次classnames(),易读性骤降 - 推荐封装一个 BEM 工具函数,而不是每个组件都手写
block变量
示例:
${block}__${element}
和 CSS Modules + BEM 混用时的常见陷阱
很多人想用 classnames 组合 CSS Modules 的 styles.xxx 和静态 BEM 类,结果发现样式没生效——问题常出在优先级或拼写。
来自 Vercel Engineering 的 React 和 Next.js 性能优化指南。用于编写、审查或重构 React/Next.js 代码以确保最佳性
- CSS Modules 默认启用局部作用域,
styles.btn是哈希后的类名,不能和手写的'btn__icon'混用 - 如果坚持 BEM 命名,建议放弃 CSS Modules 的自动哈希,改用
composes或直接写全局 CSS 文件 - 若必须混用,确保所有 BEM 类都来自同一来源:要么全走
styles导出,要么全走字符串,别交叉
性能与 Tree-shaking 注意点
classnames 本身很小(~1KB),但滥用会导致 props 重计算频繁,间接影响渲染性能。
- 避免在 render 中实时生成新对象:
{ [bem('label')]: true }每次都新建对象,应提前计算或 memo 化 - 不推荐把整个
classnames()调用包进useMemo,除非内部依赖复杂;简单布尔控制直接写更清晰 - 项目用 Webpack/Vite 时,
classnames默认支持 tree-shaking,但别 import 整个命名空间:import * as classNames from 'classnames'会阻止摇树
BEM 的本质是约定,不是语法。用 classnames 的时候,真正难的是保持块名一致性、约束修饰符命名规则,这些没法靠工具自动检查。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










