• 请教一个关于useEffect 依赖的问题
  • 发布于 2个月前
  • 107 热度
    5 评论
请教一个关于 useEffect 依赖的问题。最近在学习 react 和 nextjs ,算初学者,感觉我写的很多 useEffect eslint 都提示缺少依赖,但其实我觉得写的依赖已经够了。比如这样:
  const [conversation, setConversation] = useState<Conversation[]>([])
  useEffect(() => {
    if (currentChatTitle) {
      setConversation(
        conversation.map((i) => {
          return {
            ...i,
            title: i.id === currentChatId ? currentChatTitle : i.title,
          }
        })
      )
    }
  }, [currentChatId, currentChatTitle])
eslint 就说缺少conversation这个依赖,但是加了之后就无限执行这个 useEffect 回调了,其实我连这个currentChatId都不想加入依赖。eslint 也给了解决方案就是改成setXXX((prev)=>xxx),但这样好麻烦啊,或者就是 disable 掉这一行
  useEffect(() => {
    if (currentChatTitle) {
      // 改成`setXXX((prev)=>xxx)`
      setConversation((conversation) =>
        conversation.map((i) => {
          return {
            ...i,
            title: i.id === currentChatId ? currentChatTitle : i.title,
          }
        })
      )
    }
  }, [currentChatId, currentChatTitle])
请问下各位平时会关掉这个eslintreact-hooks/exhaustive-deps这个规则吗?

用户评论
  • 尘世无情
  • set 函数可以传入一个函数作为参数,也很清晰啊,这个更新函数接受旧值,返回新值,而且还更安全。如果 set 函数传入值,获取到外面的旧的 conversation 怎么办,传入函数就没问题了,上面有人推荐使用 useMemo ,我不太建议,看起来你的这更新就是数组替换一下,这个渲染也不太复杂,没有必要缓存,缓存本身也是有成本的,无脑 useMemo 不是全是好处的,不考虑本身的成本,心智负担还变重了。
  • 2025/2/23 18:29:00 [ 0 ] [ 0 ] 回复
  • 千帆過盡
  • eslintreact-hooks/exhaustive-deps 规则应该设置报 warning ,不要报 error 。
    多个 state 有时候是可以合并成一个的,某些情况可以解决 useEffect 依赖报 warning 。
    明确知道自己逻辑正确的时候,忽略 warning 就好了,react 写多了就习惯了
  • 2025/2/23 18:27:00 [ 0 ] [ 0 ] 回复
  • 半生輕狂客
  • react 的心智负担很大,往往对初学者不友好,首先,开发者理解的依赖和 react 需要的依赖是不一样的,你这个代码想在 currentChatId, currentChatTitle 变化时执行函数,但是每次函数更新时,conversation 因为在副作用引用了,也会更新,所以也需要监听,合理的办法确实是通过 setConversation 返回当前值进行更新。

    如果你连 currentChatId 都不想加,说明 currentChatId 本身是常量或者不更新的值,你应该使用 useMemo 包裹起来,避免重复计算,eslint 的规则不能关闭,他确实能反映依赖的问题,但是 ahooks 是必须使用的,作为 react 的 hooks 包装,能节省很多代码,另外你这个写法是不能够优化,currentChatTitle 在什么时候更新?初始化更新应该放在 useMount 上,事件触发应该放在函数里,这种情况的副作用不多见。
  • 2025/2/23 18:23:00 [ 0 ] [ 0 ] 回复
  • 山有木兮
  • 就得用后面这段方案。否则的话,前面那个例子能跑通的原因也只是碰巧了,在于 每次因为其他 state 的变化导致的组件 rerender ,顺便更新了你的这个 useEffect 中的 conversation 。如果你用前面的方式发现某次显示的 conversation 是旧数据,那么就是掉坑里了。至于这个场景,我感觉可以试一下用 useMemo 。如果是要根据两个条件来筛选当前 active 的 conversation 或者类似的,那就
    const activeConversation = useMemo(() => {
    // 在这里面 map
    }, [conversation, xxx_id, xxx_title]);
    这样还能节约一次重绘,useEffect 那种 set 状态相当于 中括号里的变量变化一次重绘,useEffect 触发完因为 set 了 state 又触发一次重绘。useMemo 则可以是 一次绘制里面直接根据中括号里面的值,这一轮绘制就给变化的结果返回去。
  • 2025/2/23 18:20:00 [ 0 ] [ 0 ] 回复