React自定义Hook闭包问题:curPage无法正确递增
React自定义Hook闭包问题解析与修复
问题原因
你遇到的核心问题是React组件渲染机制与闭包结合导致变量无法持久化:
- 组件每次重新渲染时,
usePaginationHook会被重新执行,函数内部的let curPage = 1;会被重新初始化,每次渲染都会得到一个全新的curPage变量。 getItems是Hook每次执行时创建的新函数,它捕获的是当前渲染周期内的curPage。调用getItems时,虽然会把当前的curPage从1加到2,但这个修改只存在于当前渲染的变量副本中。- 一旦
setItemsToRender触发组件重新渲染,usePagination再次执行,curPage又被重置为1,导致下次调用getItems时仍从1开始累加,永远停在2。
把curPage移到全局能正常工作,是因为全局变量不会随组件渲染重置,但这种写法会导致多个组件共用同一个curPage,完全破坏了自定义Hook的复用性,绝对不推荐。
正确修复方案
要在Hook中持久化跨渲染的变量,应该使用React提供的useState或useRef,根据需求选择:
方案1:用useState管理curPage(推荐,适合需要同步视图更新的场景)
import { useState } from 'react'; const usePagination = items => { const [itemsToRender, setItemsToRender] = useState(items.slice(0, 4)); // 用useState持久化curPage,初始值设为1 const [curPage, setCurPage] = useState(1); const maximumItems = 4; const totalPages = Math.ceil(items.length / maximumItems); const getItems = () => { const nextPage = curPage + 1; // 增加页数判断,避免超过总页数后无效调用 if (nextPage > totalPages) return; const min = (nextPage - 1) * maximumItems; const max = nextPage * maximumItems; setItemsToRender(state => state.concat(items.slice(min, max))); setCurPage(nextPage); }; return { getItems, itemsToRender, curPage, totalPages }; }; export default usePagination;
useState保存的curPage会在组件整个生命周期内保持状态,每次更新通过setCurPage触发,确保跨渲染周期的一致性。- 新增的页数判断能防止超出总页数后继续调用导致的逻辑错误。
方案2:用useRef管理curPage(适合curPage变化不需要触发视图更新的场景)
如果组件不需要根据curPage的变化重新渲染,仅在内部逻辑中使用,可以用useRef:
import { useState, useRef } from 'react'; const usePagination = items => { const [itemsToRender, setItemsToRender] = useState(items.slice(0, 4)); // 用useRef持久化curPage,.current属性保存实际值 const curPageRef = useRef(1); const maximumItems = 4; const totalPages = Math.ceil(items.length / maximumItems); const getItems = () => { curPageRef.current += 1; if (curPageRef.current > totalPages) { curPageRef.current = totalPages; return; } const min = (curPageRef.current - 1) * maximumItems; const max = curPageRef.current * maximumItems; setItemsToRender(state => state.concat(items.slice(min, max))); }; // 对外暴露curPage时,返回curPageRef.current return { getItems, itemsToRender, curPage: curPageRef.current, totalPages }; }; export default usePagination;
useRef的.current属性会在组件整个生命周期中保持不变,不会随渲染重置,且修改它不会触发组件重新渲染。
关键知识点总结
- React组件每次渲染时,自定义Hook的函数体都会重新执行,内部普通变量(
let/const声明)会被重新初始化,无法跨渲染持久化。 - 只有React提供的状态管理Hook(
useState/useRef/useReducer等)能在组件多次渲染间保存值。 - 闭包捕获的是变量的引用,但如果变量在每次渲染时都被重新创建,闭包捕获的就是每次的新变量,自然无法累积更新。
内容的提问来源于stack exchange,提问作者Maciej
相关产品推荐
相关产品推荐

