记一次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 日 完美错过报道,到酒店领了房卡放完行李后直接奔向八十中拿胸牌.饭票和资料.试机时是九省联考的题,从来没做过,我 ...
随机推荐
- 解决aspnetcore-browser-refresh.js:234 WebSocket connection to 'wss://localhost:62356/Admin/' failed问题
前言 前段时间升级了Visual Studio到v17.1.1最新版本,然后今天来运行之前的一个.net5项目一直提示:aspnetcore-browser-refresh.js:234 WebSoc ...
- 1、mybatis逆向工程
mybatis逆向工程可以针对单表自动生成mybatis执行所需要的mapper.java.mapper.xml代码(dao层),可以让程序员将更多的精力放在繁杂的业务逻辑上(service层与con ...
- 图计算引擎分析——Gemini
前言 Gemini 是目前 state-of-art 的分布式内存图计算引擎,由清华陈文光团队的朱晓伟博士于 2016 年发表的分布式静态数据分析引擎.Gemini 使用以计算为中心的共享内存图分布式 ...
- ArcGIS工具 - 按字段分割图层
天下大势,合久必分,分久必合.合并.分割在GIS数据处理和管理中也十分常见,例如按行政区划名称导出多个区县行政图层.按地类名称导出多个地类图层. 功能说明 其实,在ArcGIS中除了按属性导出外,最接 ...
- A. Greatest Convex【Codeforces Round #842 (Div. 2)】
A. Greatest Convex You are given an integer \(k\). Find the largest integer \(x\), where \(1≤x<k\ ...
- 深入理解IOC并自己实现IOC容器
title: 深入理解IOC并自己实现IOC容器 categories: 后端 tags: - .NET 背景介绍 平时开发的时候我们经常会写出这种代码: var optionA=new A(...) ...
- [WPF]程序随系统自启动
代码 Microsoft.Win32.RegistryKey key = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("SOFTWARE\ ...
- YMOI 2019.6.22
题解 YMOI 2019.6.22 lia麦頔溜了,缺了lia麦頔的排名仅供参考 不过分数还是暴露无遗 T1 邪恶入侵 简易题干: 在三维空间内有一些点,点之间有双向边.每一次询问给出一个m,只有边权 ...
- 企业应用架构研究系列十三:整合EFCore&Dapper 通用ORM框架EFDapper
EntityFrameworkCore是微软官网提供的ORM框架,是轻量化.可扩展.开源和跨平台的数据访问技术框架,但是在.Net 开发圈的评论却褒贬不一.很多人认为EFCore 执行的效能比较差,很 ...
- c++ 跑酷小游戏之用户体验plus
#undef UNICODE#undef _UNICODE#include <iostream>#include <iomanip>#include <string> ...