React类组件转函数组件时useEffect获取prevProps问题求助
解决React函数组件重构中useEffect获取prevProps的问题
我来帮你梳理下问题所在,以及对应的解决方案:
问题诊断
你的代码里有几个关键问题导致了prevItems显示undefined,且无法像类组件那样监听items变化重置页码:
自定义
usePreviousHook写法错误
你内部的useEffect没有指定依赖[value],导致ref不会在props.items变化时更新;同时把这个Hook定义在组件内部,虽然能运行,但不符合复用性原则,且容易引发不必要的重新创建。useEffect依赖数组设置错误
第二个useEffect的依赖是空数组,只会在组件挂载时执行一次,后续props.items变化时不会触发,完全失去了原componentDidUpdate的监听能力。useState初始化结构错误
useState({ pager: {} })会让pager的结构变成{ pager: {} },和原类组件的state.pager(直接是分页对象)结构不一致,会导致后续分页逻辑出错。
修正后的完整代码
首先,先定义通用的usePrevious Hook(建议放在组件外部,方便复用):
const usePrevious = (value) => { const ref = useRef(); useEffect(() => { ref.current = value; }, [value]); // 仅当value变化时更新ref return ref.current; };
然后是重构后的函数组件:
function Pagination2(props) { // 修正useState初始化,和原类组件state结构保持一致 const [pager, setPager] = useState({}); const prevItems = usePrevious(props.items); // 实现原类组件的setPage方法 const setPage = (page) => { const { items, pageSize, onChangePage } = props; if (!items || items.length === 0) return; const totalItems = items.length; let currentPage = page; const totalPages = Math.ceil(totalItems / pageSize); // 边界值处理 if (currentPage < 1) currentPage = 1; else if (currentPage > totalPages) currentPage = totalPages; // 计算分页参数 const startIndex = (currentPage - 1) * pageSize; const endIndex = Math.min(startIndex + pageSize - 1, totalItems - 1); const pages = [...Array(totalPages).keys()].map(i => i + 1); // 更新分页状态 setPager({ totalItems, currentPage, totalPages, startIndex, endIndex, pages }); // 触发页码变化回调 onChangePage(currentPage); }; // 对应componentDidMount:初始化分页 useEffect(() => { if (props.items && props.items.length) { setPage(props.initialPage); } }, [props.items, props.initialPage]); // 添加依赖,确保初始值变化时能更新 // 对应componentDidUpdate:监听items变化,重置到初始页 useEffect(() => { // 排除第一次渲染时prevItems为undefined的情况 if (prevItems !== undefined && props.items !== prevItems) { setPage(props.initialPage); } }, [props.items, prevItems, props.initialPage]); // 添加必要依赖 // 这里返回分页组件的JSX(根据你的需求自定义) return ( <div className="pagination"> {/* 示例:上一页按钮 */} <button onClick={() => setPage(pager.currentPage - 1)} disabled={pager.currentPage === 1}> 上一页 </button> {/* 页码按钮列表 */} {pager.pages?.map(pageNum => ( <button key={pageNum} onClick={() => setPage(pageNum)} style={{ backgroundColor: pager.currentPage === pageNum ? '#ccc' : 'transparent' }} > {pageNum} </button> ))} {/* 下一页按钮 */} <button onClick={() => setPage(pager.currentPage + 1)} disabled={pager.currentPage === pager.totalPages}> 下一页 </button> </div> ); } // 保留原有的propTypes和defaultProps Pagination2.propTypes = { items: PropTypes.array.isRequired, onChangePage: PropTypes.func.isRequired, initialPage: PropTypes.number, pageSize: PropTypes.number, }; Pagination2.defaultProps = { initialPage: 1, pageSize: 5, };
关键说明
usePrevious的正确用法:通过useRef保存上一轮渲染的props值,仅当目标值变化时更新ref,确保拿到的是准确的前一次值。- useEffect依赖数组:必须添加相关的props作为依赖,这样React才能在这些值变化时重新执行副作用函数,实现类组件
componentDidUpdate的逻辑。 - 第一次渲染的特殊处理:因为第一次渲染时
prevItems是undefined,所以需要在判断中排除这个情况,避免不必要的页码重置。
内容的提问来源于stack exchange,提问作者idhxx
相关产品推荐
相关产品推荐

