你觉得Hooks这一点烦吗?

大家好,我卡颂。

创新互联公司是专业的钟山网站建设公司,钟山接单;提供网站设计制作、成都网站设计,网页设计,网站设计,建网站,PHP网站建设等专业做网站服务;采用PHP框架,可快速的进行钟山网站开发网页制作和功能扩展;专业做搜索引擎喜爱的网站,专业的做网站团队,希望更多企业前来合作!

昨天一个小伙伴发了一个Demo给我,让我解释下原因。

我一看,好家伙,小小一个Demo,知识点囊括了:

  • Hooks的闭包问题
  • state是如何组装的

相信看完这个Demo,对函数组件会有更深的认识。

让人懵逼的Demo

Demo包含一个按钮、一个列表。

 
 
 
 
  1.  
  2.    Add 
  3.    {list.map(val => val)} 
  4.  
 

点击按钮,调用add方法,向列表中插入一项:

 
 
 
 
  1. let i = 0; 
  2.  
  3. export default function App() { 
  4.   const [list, setList] = useState([]); 
  5.  
  6.   const add = () => { 
  7.     // ... 
  8.   }; 
  9.  
  10.   return ( 
  11.      
  12.       Add 
  13.       {list.map(val => val)} 
  14.     
 
  •   ); 
  • 显示效果:

    烧脑的地方在于,调用add方法插入的是一个「点击后会调用 add 方法的按钮」:

     
     
     
     
    1. const add = () => { 
    2.     setList( 
    3.       list.concat( 
    4.         
    5.           key={i}  
    6.           onClick={add}> 
    7.           {i++} 
    8.          
    9.       ) 
    10.     ); 
    11.   }; 

    点击Add按钮7下后的显示效果:

    那么问题来了,点击带数字按钮(会调用和点击Add按钮一样的add方法)后会有什么效果呢?

    state的组装和闭包问题

    如果你认为会插入一个新按钮:

    那就错了。

    正确答案是:点击对应按钮后list长度变为「按钮对应数字 + 1」,且最后一项的数字为「点击前最大数字 + 1」。

    比如,点击前最大数字为6

    如果点击 0,list长度变为0 + 1 = 1,且最后一项为6 + 1 = 7:

    如果点击 2,list长度变为2 + 1 = 3,且最后一项为6 + 1 = 7:

    这是两个因素共同作用的结果:

    原因分析再来看看add方法:

     
     
     
     
    1. const add = () => { 
    2.     setList( 
    3.       list.concat( 
    4.         
    5.           key={i}  
    6.           onClick={add}> 
    7.           {i++} 
    8.          
    9.       ) 
    10.     ); 
    11.   }; 

    button点击后调用add,所以会基于add所属上下文(App函数)形成闭包,闭包中包括:

    其中list与setList来自于useState调用后的返回值:

     
     
     
     
    1. const [list, setList] = useState([]); 

    一种常见的认知误区是:多次调用useState返回的list是同一个引用。

    事实上,每次调用useState返回的list都是基于如下公式计算得出的:

    所以是一个全新的对象。

    当首屏渲染时:

    1. App组件首次render
    2. 创建list = []
    3. 依赖add,形成闭包,闭包中的list = []

    接下来,点击Add按钮:

    1. 调用add方法,该方法来自于首屏渲染创建的闭包
    2. add方法中依赖的list来自于同一个闭包,所以list = []
    3. 依赖add,形成闭包,闭包中的list = []

    所以,对于按钮0,

    任何时候点击他实际上执行的都是:

     
     
     
     
    1. setList( 
    2.   [].concat( 
    3.     {i++} 
    4.   ) 
    5. ); 

    那么如何修复这个问题呢,也很简单,将setList的参数改为函数形式:

     
     
     
     
    1. // 之前 
    2. setList(list.concat({i++})); 
    3. // 之后 
    4. setList(list => list.concat({i++})); 

    函数参数中的list来自于Hooks中保存的list,而不是闭包中的list。

    总结

    由于Hooks总是在组件render时才会计算新状态,这为Hooks带来比较重的心智负担。

    相比而言,采用「细粒度更新」实现的Hooks(比如VUE的Composition API)可以实时更新状态,操作起来更符合直觉。

    在使用Hooks过程中,你有没有遇到类似的头疼问题呢?

    参考资料

    [1]React技术揭秘:

    https://react.iamkasong.com/state/mental.html#%E5%90%8C%E6%AD%A5%E6%9B%B4%E6%96%B0%E7%9A%84react

    当前文章:你觉得Hooks这一点烦吗?
    文章地址:http://www.shufengxianlan.com/qtweb/news4/14404.html

    网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

    广告

    声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联

    猜你还喜欢下面的内容

    python知识

    同城分类信息