版本: [email protected]
我看源码就是先 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
}

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

{props.num}

)
}

setTimeout(() => {
__setNum(1000)
}, 1000)

闭包

新状态组件的 useEffect 和旧状态组件的 cleanup 同时被你 debugger 到了

从 chrome 的 debugger 工具看,这个 props 确实是来源于闭包,thanks!!

我这里也有一个闭包的问题, codesandbox.io/p/sandbox/zuo-yong-yu-de-wen-ti-kvt3jp?file=%2Fsrc%2FApp.js

react 的函数组件让人恼火,各种潜在的问题

#4 你比 OP 还新手

可以详细说说吗,不要只输出态度..

#4 就是闭包的问题。每次组件状态变化,函数都会执行一次。所以最新的状态都在最新的一次执行里。但是这里你 keydown 监听的是第一次函数运行的函数。那个函数的闭包上下文里,state 是最初的。

新手不要直接用 useEffect 。找个 react-use ahook 啥的。用封装好的 hook 。无论什么水平,写的好的话,需要手写 useEffect 的很少

你这个我觉得无解,可行的解法你自己注释里都写了
或者干脆就从 dom 里拿 v

(变量)代码在写下来的时候就被捕获了。或者说,在这个函数的生命周期里,函数内部的那个 props 就只有传入的 props

注释是啥意思,正确方式就是 ref 或者让 effect 依赖 v 啊

当时出问题的时候,我就意识到是闭包问题了,百分之九十九函数组件的问题就是闭包问题 🤣

我这个代码,从语义上来说非常简单也很实际,「页面初始化后监听回车事件」,用函数组件就是写不出来,用类组件就没有这种问题。
所以我现在写代码都少用 hook ,它改变了代码作为领域知识的意义,变成为框架去改变业务含义,导致现在都是在写框架代码,不是写业务代码。

我希望代码表达正确的「语义」

#8 是的,我想了很久,无解

感谢 🙏🏻

你说 v 不能放 useRef 里,那可以把 log 放 useRef 里
codesandbox.io/p/sandbox/zuo-yong-yu-de-wen-ti-forked-pn425w

class 组件可以是因为 this 就是 ref 啊

#15 起作用的是这个刷新 log 函数的代码吧,而且 log 可能是一个比较复杂的函数,它要拿很多个状态进行处理,这里就要依赖 v1 v2 v3 等等,容易漏

 useEffect(() => {
 logRef.current = () => {
 alert(v);
 };
 }, [v]);

#16 所以我说函数组件有额外的心智负担,容易出问题,感觉在和框架斗智斗勇 🤣

你应该在 input 标签的 onKeyDown 回调里处理你的键盘监听,而不是在 useEffect 里处理

实现方式其实很多种,难的是保留语义的前提下。我希望我的代码,别人一看,就能明白是「当页面加载后,监听回车事件并 xxx 」,如果写在 input 标签,就变成了「当这个 input 回车时,xxx 」,这里的语义就丢失了。
当然代码能跑就行,「代码表达语义」仅仅是我个人的追求。

那给你看看我改完的代码吧,个人觉得比你的语义更清晰。 codesandbox.io/p/sandbox/zuo-yong-yu-de-wen-ti-forked-6ljjys

#21 额,语义是指业务逻辑,就比如我必须表达出「当页面加载后,监听回车」,在这个前提下,如何完成需求,你的代码非常好,没有问题。只是少了「当页面加载后」的这个含义。

如果你是想要在整个页面监听回车按键,先不讨论这个需求的合理性,为了实现你要的语义清晰,你应该寻求对 hooks 的封装来实现你的 log 函数拿到最新的 state ,或者直接通过 ref 获取 input 标签当前的 value 。前者的话举一个例子: ahooks.js.org/hooks/use-memoized-fn

你这个跟他的不一样,他监听了 document ,在输入框外面 enter 也能触发

容易漏是指漏依赖? eslint 可以检查啊

#25 心智负担,而且代码会比较丑🤣

嗯,我上面也说了要想全局监听的解决方案。另外我主要想表达的是 hooks 带来的心智负担不足以成为因噎废食的理由。 这位老哥所说的“用函数组件就是写不出来”是不成立的;“hook 改变了代码作为领域知识的意义,现在都是在写框架代码,不是写业务代码”则缺少论证看起来是个人偏见。