react 新手关于 react useEffect 的困惑,为什么 useEffect 里面的 cleanup 函数里面的 props 是旧的,如何从源码解释?

249 天前
 ooo4

版本: react@18.3.1

我看源码就是先 UnmountEffects 后 MountEffects,里面也只是递归遍历而已,为什么 cleanup 里面的 props 是上一次的了?

commitPassiveUnmountEffects(root.current);
commitPassiveMountEffects(root, root.current, lanes, transitions);
// 复现的 demo
function App() {
  const [num, setNum] = useState(100)
  window.__setNum = setNum
  return <Comp num={num}></Comp>
}

function Comp(props) {
  debugger
  useEffect(() => {
    debugger
    props // {num:1000}
    return () => {
      debugger
      // 为什么这里是旧的 props? {num:100}
      props
    }
  }, [props.num])
  return (
    <p>
      <span>{props.num}</span>
    </p>
  )
}

setTimeout(() => {
  __setNum(1000)
}, 1000)
4186 次点击
所在节点    React
47 条回复
ltaoo1o
247 天前
@ljpCN #39 抱歉是没看到,你的实现很巧妙,很厉害。
ltaoo1o
247 天前
@ljpCN #40 确实是我太菜了,我很多框架、语言都写,无论 vue 、flutter 还是 swift 这些,都是有明确的 组件加载后 的语义的,我也按这个习惯来写,导致对 react 这里不熟悉,抱歉抱歉,忽略了你的消息。
demonzoo
246 天前
@ltaoo1o 哥,感谢你,可是不是我想要的 🤣 我在注释里写了不能依赖 handleKeydown 等,不然语义就变了,变成了「当 handleKeydown 」改变时,监听 keydown 事件。但是我希望表达的是「当页面加载后,监听事件」
================
听哥们一句劝,其实我觉得其他人提到的在 input 里加 onKeyDown handler 是最好的方法,但你既然要用 useEffect 那我就帮你写了一个用 useEffect 实现的方法。
40 楼的哥们说的对,你对 useEffect 的理解恐怕有点偏颇,而且我觉得你对语义的追求也有些极端,这跟 “茴字的几种写法” 有什么区别呢
最后,如果你真的采用了 useMemoizedFn 这种解法,那我觉得真的是高射炮打蚊子了,本来几行的代码非要写成一百行,应用了一堆 useRef ,useMemo ,useEffect 等 hook ,本末倒置。。。
ltaoo1o
246 天前
@demonzoo #43 是的我承认我对 useEffect 的理解不对,语义这个算个人追求,它能让我在不同框架、语言,用一套思维去写前端,也能让代码有可迁移、可维护、更好理解,当然这也是个人追求,不这样做完全是可以的,尤其是公司项目,能写完就行。
最后忘了怎么做的,是公司项目,代码比较复杂。我自己项目是抛弃了 hook ,只把 react 当视图渲染用,没有这些问题。
geekris1
246 天前
@ltaoo1o #4 一进页面就挂了 addEventListener 这时候对应函数里已经形成闭包了 没次取的 state 都是绑定那一刻 state 的值。
解决方法就是用 useRef, 写个新的 useEffect 监听 state 的变化,每次 state 更新同步更新 ref 的值 addEventListener 的函数里取 ref.current 这样就能保证每次取的都是最新的
上述操作也有对应的 hooks 工具可以参考
具体参考: https://ahooks.js.org/hooks/use-latest
Dyon
246 天前
@ltaoo1o 正确的做法是使用 jsx 的 onKeydown ,不要用 useEffect
realJamespond
246 天前
useEffect 就是变化,return 就是变化前的回调,类似还有卸载前的回调

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1102355

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX