React分页组件重构:useEffect读取propTypes属性报错求助
I see the exact issue here—you're hitting a common pitfall when transitioning from class components to function components with React Hooks. Let's break down what's going wrong and fix it step by step.
The Root Cause
Your error TypeError: Cannot read property 'items' of undefined comes from a critical mix-up: you're trying to access propTypes.items and propTypes.initialPage inside your useEffect hooks. The propTypes object is only for type validation—it doesn't hold the actual prop values being passed to your component. You need to pull these values from the props parameter instead.
On top of that, your second useEffect has invalid syntax: the first argument to useEffect is a function that doesn't receive prevProps as a parameter. To compare previous prop values, you'll need to use the useRef hook to track them.
Fixed Code Example
Here's how to adjust your code to resolve these issues:
import PropTypes from 'prop-types'; import { useState, useEffect, useRef } from 'react'; const propTypes = { items: PropTypes.array.isRequired, onChangePage: PropTypes.func.isRequired, initialPage: PropTypes.number, pageSize: PropTypes.number, }; const defaultProps = { initialPage: 1, pageSize: 5, }; function Pagination(props) { // Destructure props with fallback to default values for clarity const { items, initialPage = defaultProps.initialPage, pageSize = defaultProps.pageSize, onChangePage } = props; const [pager, setPager] = useState({}); const prevItemsRef = useRef(); // Initialize pagination on component mount (or when items/initialPage change) useEffect(() => { if (items && items.length) { setPage(initialPage); } }, [items, initialPage]); // Add dependencies to trigger effect when values change // Reset page when the items array updates useEffect(() => { // Compare current items with the stored previous version if (prevItemsRef.current && JSON.stringify(items) !== JSON.stringify(prevItemsRef.current)) { setPage(initialPage); } // Update ref to track the latest items for next render prevItemsRef.current = items; }, [items, initialPage]); // Define your setPage function (assuming this was missing from your snippet) const setPage = (pageNumber) => { const totalPages = Math.ceil(items.length / pageSize); // Update pager state with your pagination logic setPager({ currentPage: pageNumber, totalPages, // Add other pager properties as needed }); onChangePage(pageNumber); }; return ( // Your pagination JSX markup goes here <div className="pagination"> {/* Example controls */} <button onClick={() => setPage(pager.currentPage - 1)} disabled={pager.currentPage === 1}> Previous </button> <span>Page {pager.currentPage} of {pager.totalPages}</span> <button onClick={() => setPage(pager.currentPage + 1)} disabled={pager.currentPage === pager.totalPages}> Next </button> </div> ); } Pagination.propTypes = propTypes; Pagination.defaultProps = defaultProps; export default Pagination;
Key Fixes Explained
- Access props correctly: Replace
propTypes.itemswithprops.items(or use destructuring for cleaner code). ThepropTypesobject is never meant to hold actual prop values—it's just for validation. - Fix useEffect syntax: Use
useRefto track the previousitemsprop, sinceuseEffectdoesn't passprevPropsdirectly. We update the ref after each render to keep a record of the prior state. - Add proper dependencies: Both
useEffecthooks include their dependencies (items,initialPage) so they trigger correctly when these values change (this also avoids React's dependency warnings). - Optional: Destructure with defaults: Instead of relying solely on
defaultProps, setting default values directly in the function parameter destructuring makes the code more readable (thoughdefaultPropsstill works for function components if you prefer that approach).
Let me know if you hit any other snags while wrapping up the refactor!
内容的提问来源于stack exchange,提问作者idhxx

