记一次hooks陷阱
今天写一个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陷阱的问题。
...
下一次学习新技术,要谨慎。
记一次hooks陷阱的更多相关文章
- 4.Shell内部命令
4.Shell内部命令内部命令是由shell自身提供的.如果某个内部命令的名称是一个简单命令的第一个单词,shell会直接执行这个命令,而不会启动其它程序.对于一些不可能或者不方便通过外部程序实现的功 ...
- React躬行记(15)——React Hooks
Hook(钩子)是React v16.8新引入的特性,能以钩子的形式为函数组件附加类组件的状态.生命周期等特性.React的类组件有难以拆分.测试,状态逻辑分散,难以复用等问题,虽然可以通过渲染属性( ...
- 记jQuery.fn.show的一次踩坑和问题排查
最近很少已经很少用jQuery,因为主攻移动端,常用Zepto,其实很多细节和jQuery并不一样.最近又无意中接触到了PC的需求和IE6, 使用了jQuery,刚好踩坑了,特意记录一下. 本文内容如 ...
- [转]AngularJS: 使用Scope时的6个陷阱
在使用AngularJS中的scope时,会有6个主要陷阱.如果你理解AngularJS背后的概念的话,这6个点其实非常的简单.但是在具体讲述这6个陷阱之前我们先要讲两个其它的概念. 概念1: 双向数 ...
- SQL Server AlwaysON 同步模式的疑似陷阱
原文:SQL Server AlwaysON 同步模式的疑似陷阱 SQL Server 2012 推出的最重要的功能之一Alwayson,是一个集之前Cluster和Mirror于一体的新功能,即解决 ...
- shell中while循环的陷阱
在写while循环的时候,发现了一个问题,在while循环内部对变量赋值.定义变量.数组定义等等环境,在循环外面失效. 一个简单的测试脚本如下: #!/bin/bash echo "abc ...
- 精通Web Analytics 2.0 (12) 第十章:针对潜在的网站分析陷阱的最佳解决方案
精通Web Analytics 2.0 : 用户中心科学与在线统计艺术 第十章:针对潜在的网站分析陷阱的最佳解决方案 是时候去处理网站分析中最棘手的一些问题了,然后获得属于你的黑带,这是成为分析忍者的 ...
- SVN Hooks的介绍及使用
阅读此篇文章你可以: 对SVN Hooks有一定的了解 获取两个最常用的SVN Hooks案例 SVN hooks介绍 Hooks 钩子,主要实现的功能就是在特定事件发生之前或者之后自动执行事先定义好 ...
- Linux History安全问题【保存记录防止删除】+完善Linux/UNIX审计 将每个shell命令记入日志
2011-09-27 22:11:51| 分类: rhel5_033|举报|字号 订阅 Linux利用PROMPT_COMMAND实现审计功能 这个系统审计,记录什么用户,在什么时间,做 ...
- CTSC2018 & APIO2018 颓废 + 打铁记
CTSC2018 & APIO2018 颓废 + 打铁记 CTSC 5 月 6 日 完美错过报道,到酒店领了房卡放完行李后直接奔向八十中拿胸牌.饭票和资料.试机时是九省联考的题,从来没做过,我 ...
随机推荐
- PyTorch复现AlexNet学习笔记
PyTorch复现AlexNet学习笔记 一篇简单的学习笔记,实现五类花分类 这里只介绍复现的工作,如果想了解更多有关网络的细节,请去看论文<ImageNet Classification wi ...
- Jenkins&&gitlab
DevOps 强调整个组织的合作以及交付和基础设施变更的自动化 gitlab下载: 下载地址: https://docs.gitlab.com/ee/install/requirements.html ...
- python 实现DES加解密
from pyDes import * import base64 class Des3(object): def __init__(self, key, iv): # 这里密钥key长度必须为16/ ...
- vue引入高德地图
一,下载 npm install vue-amap --save 二,main.js文件内引入 import VueAMap from 'vue-amap' Vue.use(VueAMap); // ...
- day03-Spring管理Bean-IOC-01
Spring管理Bean-IOC 1.Spring配置/管理bean介绍 Bean管理包括两方面: 创建bean对象 给bean注入属性 Bean的配置方式: 基于xml文件配置方式 基于注解配置方式 ...
- 解决使用linux部署nodejs服务测试代码返回中文是乱码
今天写了个简单的node.js文件 代码如下 var http = require('http'); http.createServer(function (request, response) { ...
- flutter Error:Cannot run with sound null safety, because the following dependencies don't support
学习flutter新版本的路上,真的是一天一个新惊喜啊 今天遇到的坑是 Flutter 升级高版本后,运行和build 报错 Error: Cannot run with sound null saf ...
- 踩坑纪实----tomcat部署前端服务器不能访问中文文件夹或中文文件名问题
修改tomcat的server.xml文件(解决含有中文的文件.图片的不能下载.显示的问题): 找到下列配置信息在xml文件中的位置,添加黑体字部分的参数即可(disableUploadTimeout ...
- Mac下vscode编辑器设置
设置成中文 command + shift + p 搜索 configure langure , 点击一下 ,然后选择ZH 设置其他东西 打开配置文件:vscode菜单: Code -> ...
- 十九岁纪念|HBD To ME
过了20年,终于摆脱了令人讨厌的应试生活.19岁,一半是高三,一半是大学,由高考,分成两半.说实话,我觉得大学也没有那么令人向往,换种方式读高四吧.长大了,对时间也没有什么概念了.要不是19岁在我的家 ...