今天写一个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陷阱的问题。

...

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

最新文章

  1. Vue - 事件绑定
  2. 更换TFS账户
  3. JS BOM知识整理
  4. Spring常用的接口和类(二)
  5. HDU 4348 To the moon 可持久化线段树
  6. JSCharts
  7. Android service的开启和绑定,以及调用service的方法
  8. 《InsideUE4》UObject(三)类型系统设定和结构
  9. cobbler自动安装系统
  10. OCUpload的简单介绍与使用
  11. 浅谈session,cookie,sessionStorage,localStorage的区别及应用场景
  12. 【XSY3126】异或II 数学
  13. Mac下部署Ionic环境
  14. java项目(学习和研究)
  15. Linux内核及分析 第二周 操作系统是如何工作的?
  16. 连接查询简析 join 、 left join 、 right join
  17. 源码 time sleep
  18. jsoncpp解析拼装数组
  19. Zynq-7000 FreeRTOS(二)中断:PL中断请求
  20. 使用JSon实现三级联动

热门文章

  1. MongoDB安全加固,防止数据库攻击删除勒索威胁
  2. Jmeter 跨线程组传参
  3. [OpenCV实战]3 透明斗篷
  4. dfs学习笔记
  5. C#开发的资源文件程序(可国际化) - 开源研究系列文章
  6. absolute定位后居中的方法
  7. mysql常用命令,检查数据库连接情况以及修改时区
  8. Java语言的跨平台性-JDK,JRE和JVM
  9. 读C#代码整洁之道笔记07_代码评审和集成测试
  10. 一文搞懂工作流审批(Java+activiti)快速开发+自定义工作流配置