react 新手关于 react useEffect 的困惑,为什么 useEffect 里面的 cleanup 函数里面的 props 是旧的,如何从源码解释?
版本: [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 改变了代码作为领域知识的意义,现在都是在写框架代码,不是写业务代码”则缺少论证看起来是个人偏见。
如题,我在号称隐私保护强的 CalyxOS ( Android 13 )安装了哔哩哔哩 app ,然后浏览了几个视频,再卸载,再安装回去,结果发现它仍然保留了我卸载前的浏览记录…
新闻来源:Computer World Sun公司的JRuby团队正在离开他们的老东家Sun,投奔Engine Yard公司。他们声称这是因为Oracle并购Sun后的前途不明…
firefox:拓展未改版前,一直是 firefox 。 Chrome:干净,但垂直标签支持最差。 edge:用了很长时间,越来越多无用的特性。垂直标签支持不错,但并不完美。比…