【react 高频面试题—核心原理篇】:useEffect 的依赖项如果是数组或对象(引用类型),会有什么问题?如何解决?

面试官提问:useEffect 的依赖项如果是数组或对象(引用类型),会有什么问题?如何解决?

💡 核心回答技巧

这道题考察的是两个核心点:

  1. React 依赖检查机制 :使用的是 Object.is(浅比较)。
  2. 闭包陷阱与死循环:引用类型地址改变导致的不必要渲染或无限循环。

1. 问题的本质:浅比较(Shallow Comparison)

React 在每次渲染后会对比 useEffectdeps 数组。 对于基本类型(string, number, boolean),比较的是 。 对于引用类型(Object, Array, Function),比较的是内存地址

典型错误场景:

JavaScript

scss 复制代码
function UserProfile() {
  const [count, setCount] = useState(0);
  
  // 每次组件重新渲染,options 都会被重新创建,指向一个新的内存地址
  const options = { id: 1 }; 

  useEffect(() => {
    console.log('执行了!');
  }, [options]); // 即使 options 的内容没变,地址变了,useEffect 就会触发
}

如果 useEffect 内部又触发了状态更新,就会导致无限死循环

2. 解决方案有哪些?

方案一:使用 useMemouseCallback

这是最正统的方法,将引用类型"持久化"。

  • useMemo:缓存对象/数组。
  • useCallback:缓存函数。

JavaScript

scss 复制代码
const options = useMemo(() => ({ id: 1 }), []); 
// 只要依赖项不变,options 的引用地址在多次渲染间保持不变

方案二:属性拆解(推荐)

如果对象很大,但我只关心其中的某个属性,直接把该属性放入依赖项。

JavaScript

scss 复制代码
useEffect(() => {
  // 业务逻辑
}, [options.id]); // 监听基本类型 id,而不是整个对象

方案三:使用 useRef

如果这个变量不需要参与渲染(即它的改变不需要触发 UI 更新),可以用 useRef 存储。useRef 返回的是同一个对象引用。

方案四:对于函数,写在 useEffect 内部

如果函数只在效应内部使用,直接移进去,避免将其作为依赖。


3. 进阶追问:如果不小心造成了死循环,该如何排查?

  • React DevTools:查看哪个 Hook 的数据一直在跳动。
  • 日志大法 :在 useEffect 第一行打 console.log,看触发频率。

🌟 总结

"useEffect 的依赖项对比执行的是浅比较 。对于引用类型,即使内容一致,只要内存地址改变,效应就会重新执行。解决办法通常是使用 useMemo/useCallback 冻结引用 ,或者拆解属性,确保只有当真正相关的数据变化时,才触发逻辑。"

相关推荐
EnCi Zheng17 分钟前
M5-markconv自定义CSS样式指南 [特殊字符]
前端·css·python
kyriewen21 分钟前
你的网页慢,用户不说直接走——前端性能监控教你“读心术”
前端·性能优化·监控
广州华水科技21 分钟前
北斗GNSS变形监测在大坝安全监测中的应用与优势分析
前端
前端老石人32 分钟前
前端开发中的 URL 完全指南
开发语言·前端·javascript·css·html
CAE虚拟与现实33 分钟前
五一假期闲来无事,来个前段、后端的说明吧
前端·后端·vtk·three.js·前后端
Sarvartha44 分钟前
三目运算符
linux·服务器·前端
晓晨的博客1 小时前
ROS1录制的bag包转换为ROS2格式
前端·chrome
Wect1 小时前
LeetCode 72. 编辑距离:动态规划经典题解
前端·算法·typescript
donecoding1 小时前
别再让 pnpm 跟着 nvm 跑了!独立安装终极指南
前端·node.js·前端工程化
GISer_Jing1 小时前
AI全栈转型_TS后端学习路线
前端·人工智能·后端·学习