在React中使用useRef()相比模块作用域声明变量有哪些优势?
模块作用域声明变量与组件内useRef存储实例的额外差异
除了作用域限制之外,二者还有四个核心差异:
- 生命周期与实例复用逻辑不同
模块作用域声明的webClient是全局单例:整个模块仅在首次导入时初始化一次,所有复用的组件实例、甚至同模块内导出的其他组件/函数,都会共享同一个实例。如果修改这个实例的配置(比如新增axios拦截器、修改baseURL),所有用到该实例的地方都会受影响。
而useRef存储的实例是每个组件实例独有的:每渲染一个该组件的实例,就会单独生成一个新的webClient,各个组件实例的配置完全隔离,修改其中一个不会影响其他,组件销毁后对应实例也会被垃圾回收,不会残留无用内存。 - 初始化时机不同
模块作用域变量的初始化发生在模块被导入时,哪怕你从来没有实际渲染过这个组件,只要导入了该模块,实例就已经被创建,会产生不必要的初始化开销,尤其当初始化逻辑较重时会拖慢模块加载速度。
而useRef的初始化仅在组件首次渲染时触发,只有组件真的被挂载使用时才会生成实例,没有冗余开销。 - SSR(服务端渲染)兼容性不同
模块作用域的单例在SSR场景下会出现跨请求污染问题:服务端进程是长期运行的,所有用户的请求都会复用同一个模块实例,如果webClient中存储了用户专属的授权信息、请求上下文,多个用户的请求就会互相串数据,严重时会引发信息泄露。
而useRef存储的实例随每次组件渲染(对应SSR场景下每次请求的组件渲染)独立生成,不会出现跨请求数据污染的问题,SSR适配性更好。 - 开发环境热重载表现不同
开发环境开启模块热重载(HMR)时,修改组件代码后模块作用域的变量不会被重新初始化,会一直沿用首次导入时生成的旧实例,很容易出现缓存异常,比如修改了axios的默认配置后不生效、之前的拦截器残留等问题。
而useRef的实例会随着热重载后的组件重新初始化,永远符合当前代码的预期逻辑,不会有缓存遗留问题。
内容的提问来源于stack exchange,提问作者Archimedes Trajano
相关产品推荐
相关产品推荐

