记一次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陷阱的问题。
...
下一次学习新技术,要谨慎。
最新文章
- Vue - 事件绑定
- 更换TFS账户
- JS BOM知识整理
- Spring常用的接口和类(二)
- HDU 4348 To the moon 可持久化线段树
- JSCharts
- Android service的开启和绑定,以及调用service的方法
- 《InsideUE4》UObject(三)类型系统设定和结构
- cobbler自动安装系统
- OCUpload的简单介绍与使用
- 浅谈session,cookie,sessionStorage,localStorage的区别及应用场景
- 【XSY3126】异或II 数学
- Mac下部署Ionic环境
- java项目(学习和研究)
- Linux内核及分析 第二周 操作系统是如何工作的?
- 连接查询简析 join 、 left join 、 right join
- 源码 time sleep
- jsoncpp解析拼装数组
- Zynq-7000 FreeRTOS(二)中断:PL中断请求
- 使用JSon实现三级联动