React分页组件Props不更新,过滤与分页共用数据求助
解决方案
核心问题是分页组件未随过滤后的数据更新重新渲染,且数据拆分逻辑放在子组件导致数据流混乱。推荐将过滤、分页的核心逻辑统一放在父组件管理,让子组件仅负责UI渲染,具体实现如下:
1. 父组件统一状态管理
在主组件中维护以下状态与派生数据:
allPokemons:存储原始的全部宝可梦数据filterQuery:绑定输入框的过滤关键词currentPage:当前选中的页码- 用
useMemo计算filteredPokemon:基于原始数据和过滤关键词得到过滤后的列表 - 用
useMemo计算currentPokemons:基于过滤后的列表和当前页码,拆分出当前页需要展示的片段
这样过滤操作会触发filteredPokemon更新,同时重置页码到第一页,确保分页数据同步更新。
2. 改造子组件职责
- PokemonBio:直接接收
currentPokemons作为props,负责渲染当前页的宝可梦列表 - Pagination:接收总条目数、每页条目数、当前页码和页码切换回调,仅负责渲染页码按钮并触发切换事件,不再处理数据拆分逻辑
代码示例
父组件(PokemonList.jsx)
import { useState, useMemo } from 'react'; import PokemonBio from './PokemonBio'; import Pagination from './Pagination'; const ITEMS_PER_PAGE = 10; function PokemonList() { const [allPokemons, setAllPokemons] = useState([]); // 假设已初始化原始宝可梦数据 const [filterQuery, setFilterQuery] = useState(''); const [currentPage, setCurrentPage] = useState(1); // 计算过滤后的宝可梦列表 const filteredPokemon = useMemo(() => { if (!filterQuery) return allPokemons; return allPokemons.filter(pokemon => pokemon.name.toLowerCase().includes(filterQuery.toLowerCase()) ); }, [allPokemons, filterQuery]); // 计算当前页需展示的宝可梦片段 const currentPokemons = useMemo(() => { const startIndex = (currentPage - 1) * ITEMS_PER_PAGE; return filteredPokemon.slice(startIndex, startIndex + ITEMS_PER_PAGE); }, [filteredPokemon, currentPage]); // 页码切换回调 const handlePageChange = (page) => { setCurrentPage(page); }; // 过滤输入变化回调,同时重置页码到第一页 const handleFilterChange = (e) => { setFilterQuery(e.target.value); setCurrentPage(1); }; return ( <div> <input type="text" value={filterQuery} onChange={handleFilterChange} placeholder="搜索宝可梦..." /> <PokemonBio pokemons={currentPokemons} /> <Pagination totalItems={filteredPokemon.length} itemsPerPage={ITEMS_PER_PAGE} currentPage={currentPage} onPageChange={handlePageChange} /> </div> ); } export default PokemonList;
分页组件(Pagination.jsx)
function Pagination({ totalItems, itemsPerPage, currentPage, onPageChange }) { const totalPages = Math.ceil(totalItems / itemsPerPage); // 只有一页时不显示分页 if (totalPages <= 1) return null; const pages = Array.from({ length: totalPages }, (_, idx) => idx + 1); return ( <div className="pagination"> {pages.map(page => ( <button key={page} onClick={() => onPageChange(page)} disabled={page === currentPage} style={{ margin: '0 4px', padding: '4px 8px', cursor: page === currentPage ? 'default' : 'pointer', backgroundColor: page === currentPage ? '#ddd' : '#fff' }} > {page} </button> ))} </div> ); } export default Pagination;
方案优势
- 数据流清晰:所有状态与逻辑集中在父组件,避免子组件间的状态传递混乱
- 性能优化:
useMemo确保仅当依赖数据变化时才重新计算派生状态 - 符合用户预期:过滤操作自动重置到第一页,避免出现过滤后页码超出范围的问题
- 组件职责单一:子组件仅负责UI渲染,便于维护和复用
内容的提问来源于stack exchange,提问作者ZoEM
相关产品推荐
相关产品推荐

