导出类与直接导出对象实例的差异、实例生命周期及方案优缺点分析
首先先明确两种导出写法的核心差异:
/** 你的实现方式 **/ export default Example // 导出类本身,实例化时机由调用方控制 /** 单例导出实现方式 **/ export default new Example() // 导出提前实例化的单例对象
直接导出的对象实例的生命周期
ES 模块本身具备单例加载的特性,该实例会在模块第一次被其他文件导入时完成初始化,后续所有文件导入该模块时,拿到的都是同一个实例对象,实例会一直存活到应用进程终止(浏览器端对应页面刷新、页面关闭,Node端对应服务进程停止),和 React 组件树的生命周期完全无关,即便 React 根组件卸载重渲染,该实例的状态也不会发生变化。
单例导出方式的弊端
如果是无状态、不需要动态配置的工具类对象,单例导出确实使用更简便,但对于你当前绑定登录态的 Client 场景,存在以下明显问题:
- 无法适配动态初始化需求:你的场景需要在用户登录时才能拿到 token、用户身份等 Client 必需的配置参数,提前导出实例的话,初始化时没有登录信息,生成的实例本身不可用。后续切换账号、退出重登等场景下,全局单例也无法自动更新,很容易残留上一个用户的状态,引发权限错误。
- 不利于单元测试:测试过程中如果需要模拟不同登录态、不同配置的 Client 实例,全局单例需要在每个测试用例结束后手动清理状态,否则会出现用例之间的状态污染。如果导出的是类,每个测试用例可单独实例化新对象,天然实现状态隔离。
- 无法自动触发 React 组件更新:通过 Context 传递实例时,实例更新后所有消费组件会自动重渲染拿到最新值;而全局单例的状态变更不会触发 React 的更新逻辑,很容易出现组件还拿着旧的失效 Client 发请求的问题。
- 不兼容 SSR 场景:如果后续你的 React 应用需要做服务端渲染,服务端进程会接收多个用户的请求,全局单例会把不同用户的 Client 实例混淆,导致用户数据串号的严重安全问题,Context 是请求级隔离的,不存在该问题。
内容的提问来源于stack exchange,提问作者konsalex
相关产品推荐
相关产品推荐

