首页 > 其他分享 >记一次hooks陷阱

记一次hooks陷阱

时间:2023-02-19 23:23:35浏览次数:26  
标签:pageIndex 一次 const setPageIndex hooks loadNextPage rows 陷阱

今天写一个hook,正想发挥hooks这种高级复用方式来缩短我的开发时间,就出现了一个新bug。

我编写的这个hook用于管理数据列表状态。除了导出内部的状态外,还导出一些方法供外部调用。代码简化如下:

function useDataList() {
  const [rows, setRows] = useState([])
  const [pageIndex, setPageIndex] = useState(0)
  async function loadNextPage() {
    const res = await api.searchData(pageIndex+1)
    setRows(res.data.rows)
    setPageIndex(index+1)
  }
  return {
    rows,
    setPageIndex,
    nextPage
  }
}

然后这样使用这个hook:

function App() {
  const {rows, setPageIndex, loadNextPage} = useDataList()
  useEffect(()=>{
    setPageIndex(-1) // 因为loadNextPage中会给pageIndex加一,而初始我们希望请求第0页,因此设为-1
    // 因为setPageIndex()不会立刻改变pageIndex,因此要在下一个事件循环调用loadNextPage()
    setTimeout(()=>{
      loadNextPage()
    })
  }, [])

  return (
    {/* 这里使用rows渲染列表 */}
  )
}

好,现在问题出现了。api.searchData()请求的是第1页,而不是第0页,你知道为什么吗?

 

原因就在于产生了闭包。

useEffect在App第一次渲染的时候执行,以后不再执行。

这时loadNextPage指向的是第一次App()指向时的loadNextPage,

而这个loadNextPage是第一次执行useDataList时导出的,

它内部的pageIndex保存的是第一次执行useDataList()时的pageIndex的值,也就是0。

因此调用loadNextPage()时,请求的页码是pageIndex+1=0+1=1。

我这种情况和网上说的hooks陷阱有点不一样,但是原理是一样的,都是闭包问题。

 

查阅资料发现,可以使用ahooks的useMemorizedFn解决这个问题。

这个API可以保持传入的函数不变,但是每次函数执行时访问的都是最新的state。

于是代码这样改:

function App() {
  const {rows, setPageIndex, loadNextPage} = useDataList()
  const wrapedLoadNextPage = useMemorized(()=>{
    loadNextPage()
  })
  useEffect(()=>{
    setPageIndex(-1)
    setTimeout(()=>{
      wrapedLoadNextPage()
    })
  }, [])
  return (
    {/* 这里使用rows渲染列表 */}
  )
}

 

最后感叹一下,原本以为新技术哪有什么难的,只要迁移以前的知识就行了呗。

结果发现,同一个功能点,用不同的技术实现就是有差别,新的技术产生新的问题,从而导致项目延期。

比如会使用vue开发网页,使用rn开发APP问题应该不大,结果rn的语法和vue不同。

又比如使用uniapp开发过小程序,那使用rn开发APP应该会挺快,结果RN的生态真的简陋,没有uniapp那么齐全方便。

再比如hooks解决了class组件复用上的一些问题,那用起来应该很顺手,结果出了今天的hooks陷阱的问题。

...

下一次学习新技术,要谨慎。

标签:pageIndex,一次,const,setPageIndex,hooks,loadNextPage,rows,陷阱
From: https://www.cnblogs.com/hdxg/p/17135909.html

相关文章

  • 设置用户第一次登录强制更改密码
    #新建用户:useraddtest#设置初始密码:echo“123456”|passwd--stdintest#设置用户下次登录需要更改密码chage-d0test关于chagechage--help用法:chage[选项]......
  • react中Hooks的理解和用法
    一、Hooks是什么?Hook 是React16.8的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性至于为什么引入hook,官方给出的动机是解决......
  • NJUPT自控第一次积分赛的小总结(二)基于simpleFOC的无刷电机控制
    新人一枚,写的比较水,欢迎大佬指正!先说一下我用的物料与开发环境吧:无刷电机:makerbase的2804电机(带AS5600磁编码器)电机驱动板:simpleFOCmini(学校推荐的)......
  • k8s学习-记录一次集群kube-controller,scheduler等多个pod重启的问题解决
    问题一次,集群的kube-controller,scheduler等容器重启,查看日志,发现时间很集中,在秒级范围内多个pod同时重启。查看pod状态kubectlgetpod-nkube-system|grepkube-contro......
  • 算法刷题-只出现一次的数字、输出每天是应该学习还是休息还是锻炼、将有序数组转换为
    只出现一次的数字(位运算、数组)给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。说明:你的算法应该具有线性时间复......
  • 记录一次内网环境配置
    前言因为近期有需要,在内网进行轻量编程办公,期间遇到一点问题和自己做的步骤记录下来,便于后期回顾。安装编译器VSCode编译器首选的还是VScodehttps://code.visualstudi......
  • 再来一次基础数论全家桶
    约数相关\(\mathcal{gcd}\)我100年前的证明自己都已经看不懂了,所以我们这里再浅浅的证明一下。好,于是就可以用递归求\(\mathcal{gcd}\)了。i64gcd(i64a,i64b){......
  • 一次web系统的nginx配置恢复
    前言:组里有一个小伙子,为了升级nodejs,安装各种库,把系统给搞崩溃了,无法登录。找运维人员也不行,最后的解决办法换一台机器。幸好原来只有一块盘,所以数据还在。 $mva/b/......
  • vue2 - $nextTick 在下一次DOM更新结束后 指定其回调
    Vue实现响应式并不是数据发⽣变化之后DOM⽴即变化,⽽是按⼀定的策略进⾏DOM的更新。$nextTick是在下次DOM更新循环结束之后执⾏延迟回调,在修改数据之后使⽤$next......
  • 记一次定位偶发崩溃问题
    本文记录定位偶发崩溃问题的全过程,并给出相关建议,沉淀经验。背景描述测试反馈,通过右键添加股票,有一定概率闪退,没有dump以及更多的信息,崩溃频率随机。问题复现同测试进......