当前位置: 首页 > 科技观察

你觉得Hooks很烦人吗?

时间:2023-03-13 21:30:00 科技观察

大家好,我是Kason。昨天有朋友给我发了一个demo,我来解释一下原因。看到了,好人,一个小Demo,知识点包括:Hooks闭包问题state是如何组装的相信看完这个Demo,你会对功能组件有更深的理解。令人困惑的DemoDemo包含一个按钮和一个列表。Add{list.map(val=>val)}

点击按钮,调用add方法,向列表中插入一个item:leti=0;exportdefaultfunctionApp(){const[list,setList]=useState([]);constadd=()=>{//...};return(Add{list.map(val=>val)}
);}显示效果:烧脑的地方是调用add方法插入一个"button,之后会调用add方法点击":constadd=()=>{setList(list.concat({i++}));};点击添加按钮7次后的显示效果:那么问题来了,点击带有数字的按钮会是什么效果(会调用和点击添加按钮一样的add方法)?状态装配和关闭问题如果您认为会插入一个新按钮:那您就错了。正确答案是:点击对应的按钮后,列表长度变为“按钮对应的数字+1”,最后一项的数字为“点击前最大的数字+1”。比如点击前最大数为6,如果点击0,则列表长度变为0+1=1,最后一项为6+1=7:如果点击2,则列表长度变为2+1=3,最后一项是6+1=7:这是两个因素的结果:Hooks的闭包问题和state是如何组装的分析再来看add方法:constadd=()=>{setList(list.concat({i++}));};点击按钮后会调用add,所以会根据add所属的上下文(App函数)形成一个闭包。闭包包括:addlistsetListi属于模块级作用域,不在闭包中。list和setList来自useState调用后的返回值:const[list,setList]=useState([]);一个常见的认知误区是:多次调用useState返回的列表是同一个引用。事实上,每次调用useState返回的list都是根据下面的公式计算出来的:basestate+update1+update2+...=currentstate,所以是一个全新的对象。如果想了解更详细的update和state计算,可以参考React技术揭秘[1]首屏渲染时:Appcomponentfirstrendercreateslist=[]Add依赖于add,形成一个闭包,在闭包中列出=[]接下来,点击添加按钮:调用add方法,该方法来自首屏渲染创建的闭包。add方法中的list来自同一个闭包,所以list=[]{i++}依赖add形成一个闭包,list中的closure=[]所以,对于按钮0,任何时候你点击它实际上是执行是:setList([].concat({i++}));那么如何解决这个问题也很简单,把setList的参数改成函数的形式://beforesetList(list.concat({i++}));//在setList(list=>list.concat({i++}));函数参数中的列表来自Hooks中保存的列表,而不是闭包中的列表。总结由于Hooks总是在渲染组件时计算新的状态,这给Hooks带来了沉重的精神负担。相比之下,用“细粒度更新”实现的Hooks(比如VUE的CompositionAPI)可以实时更新状态,操作更直观。在使用Hooks的过程中,你有遇到过类似的头痛问题吗?参考[1]React技术秘籍:https://react.iamkasong.com/state/mental.html#%E5%90%8C%E6%AD%A5%E6%9B%B4%E6%96%B0%E7%9A%84反应