react/only-export-components 限制
它的作用
确保模块仅 导出 React 组件(及相关 HMR 安全项),以便 Fast Refresh(即热重载)能够安全地保留组件状态。具体而言,它会验证模块的导出结构以及常见入口点(如 createRoot(...).render(<App />))是否符合 react-refresh 等集成工具所期望的格式。
此规则基于 eslint-plugin-react-refresh 中的规则。
为什么这是个问题?
Fast Refresh 只有在模块仅导出组件且避免混淆刷新运行时的模式时,才能可靠地保持状态。存在隐患的模式(如 export *、匿名默认函数、导出 JSX 数组,或以不受支持的方式混合非组件导出)可能导致:
- 编辑后组件重新挂载并丢失状态
- 更新被遗漏(无刷新)或过度重新加载
- HMR 行为脆弱,不同打包工具之间表现不一致
通过强制使用可预测的导出方式,开发期间的修改将保持快速且具有状态感知性。
示例
以下为 不正确 的代码示例:
// 1) 以不受支持的方式将工具函数与组件混合导出
export const foo = () => {}; // 工具函数,不是组件
export const Bar = () => <></>; // 组件// 2) 匿名默认导出(名称是必需的)
export default function () {}// 3) 重导出全部内容会隐藏实际导出内容
export * from "./foo";// 4) 导出 JSX 集合会使组件无法被发现
const Tab = () => null;
export const tabs = [<Tab />, <Tab />];// 5) 在定义组件的同一模块中启动根节点
const App = () => null;
createRoot(document.getElementById("root")).render(<App />);以下为 正确 的代码示例:
// 命名导出或默认导出的组件均可接受
export default function Foo() {
return null;
}// 除非选项明确允许或命名约定允许,否则工具函数可共存
const foo = () => {};
export const Bar = () => null;// 入口文件可渲染导入的组件
import { App } from "./App";
createRoot(document.getElementById("root")).render(<App />);配置
此规则接受一个配置对象,包含以下属性:
allowConstantExport
type: boolean
default: false
允许在不触发违规的情况下,与组件导出一起导出原始常量(字符串/数字/布尔值/模板字面量)。当你的打包工具的 Fast Refresh 集成支持此功能时(由插件的 vite 预设启用),建议开启。
// 当 allowConstantExport: true 时允许
export const VERSION = "3";
export const Foo = () => null;allowExportNames
type: string[]
default: []
将特定命名导出视为 HMR 安全(适用于某些框架中需要热替换特定导出的情况)。例如,在 Remix 中:{ "allowExportNames": ["meta", "links", "headers", "loader", "action"] }
checkJS
type: boolean
default: false
检查包含 JSX 的 .js 文件(除了 .tsx/.jsx 文件)。为减少误报,启用后仅检查导入了 React 的文件。
customHOCs
type: string[]
default: []
如果你导出的是经过自定义高阶组件包装的组件,请在此列出其标识符,以避免误报。
如何使用
要通过配置文件或 CLI 启用 此规则,可以使用:
{
"plugins": ["react"],
"rules": {
"react/only-export-components": "error"
}
}oxlint --deny react/only-export-components --react-plugin