添加第6张电影卡片时按IMDb评分乱序?React组件问题排查
问题排查:添加第6张电影卡片后排列顺序异常
原本添加电影时卡片按添加顺序排列,但添加第6张后,卡片会自动按IMDb评分降序打乱排列,以下是电影列表组件代码:
const MoviesList = (props) => { const [search, setSearch] = useState('') const [filterBy, setFilterBy] = useState([]) const [orderBy, setOrderBy] = useState('') const movies = useSelector((state) => { //console.log(state.movies) return state.movies }) const handleChange = (e) => { const inputValue = e.target.value setSearch(inputValue) //filtering the movies based on the search value const filteredValue = movies.filter((movie) => { return movie.Title.toLowerCase().includes(inputValue) }) setFilterBy(filteredValue) } const handleSelectChange = (e) => { setOrderBy(e.target.value) } const show = (movies) => { //sorting based on orderBy switch (orderBy) { case 'a-z': return [].concat(movies).sort((a, b) => a.Title.localeCompare(b.Title)) case 'z-a': return [].concat(movies).sort((a, b) => b.Title.localeCompare(a.Title)) case '1-10': return [].concat(movies).sort((a, b) => a.imdbRating - b.imdbRating) case '10-1': return [].concat(movies).sort((a, b) => b.imdbRating - a.imdbRating) default: return [].concat(movies) } } return ( <div className='container'> <div className='d-flex mb-3 '> <h1 style={{ textAlign: 'center',border:'solid 3px',borderBlockColor:'bs-purple',backgroundColor:'#BFB9FA',position:'sticky' }} >My Movie List</h1> <form style={{ float: 'right', marginRight: '35px',top:'80px',right:'5px',position:'absolute' }}> <input type="text" placeholder='search by name' value={search} onChange={handleChange} className="mr-4" style={{borderRadius:7,width:'300px',padding:'3px',marginRight:'15px'}}/> <select value={orderBy} onChange={handleSelectChange} style={{padding:'3px',borderRadius:7,width:90}} > <option value="">orderBy</option> <option value="a-z">a-z</option> <option value="z-a">z-a</option> <option value="1-10">1-10</option> <option value="10-1">10-1</option> </select> </form> </div> <div className="pt-2 justify-content-center " style={{textAlign:'center',width:'70%',display: "flex", flexWrap: "wrap", justifyContent: "center ",alignItems:'stretch'}}> { filterBy.length > 0 ? ( filterBy.map((movie) => { return <MovieCard key={movie.imdbID} Poster={movie.Poster} Title={movie.Title} imdbRating={movie.imdbRating} imdbID={movie.imdbID} /> }) ) : ( show(movies).map((movie) => { return <MovieCard key={movie.imdbID} {...movie} /> }) ) } </div> </div > ) } export default MoviesList
添加4张卡片时的效果:
添加6张卡片时的效果:
问题根源
filterBy状态未同步movies更新:filterBy仅在输入框变化时更新,添加新电影时若未触发输入框操作,filterBy会保持旧数组状态。当filterBy长度小于最新的movies数组长度时,组件会走show(movies)分支渲染列表。- 默认排序依赖原数组顺序:
show函数默认分支仅返回原数组拷贝,若Redux中movies数组的添加顺序被意外修改(或orderBy状态被误设为10-1),就会出现评分降序排列的情况。
解决方案
- 自动同步
filterBy与movies:用useEffect监听movies和search的变化,当搜索框为空时自动更新filterBy为最新电影列表:
import { useEffect } from 'react'; // 在组件内部添加 useEffect(() => { if (search === '') { setFilterBy([...movies]); } }, [movies, search]);
这样无论是否触发搜索框,只要添加新电影,filterBy都会同步更新,确保渲染最新的添加顺序列表。
- 强制保持添加顺序:给每个电影对象添加
addedAt时间戳(在添加电影的Redux action中),并在默认排序时以此为依据:
// 添加电影的action示例 const addMovie = (movie) => ({ type: 'ADD_MOVIE', payload: { ...movie, addedAt: Date.now() } }); // 修改show函数的default分支 const show = (movies) => { switch (orderBy) { // 原有case保持不变 case 'a-z': return [].concat(movies).sort((a, b) => a.Title.localeCompare(b.Title)) case 'z-a': return [].concat(movies).sort((a, b) => b.Title.localeCompare(a.Title)) case '1-10': return [].concat(movies).sort((a, b) => a.imdbRating - b.imdbRating) case '10-1': return [].concat(movies).sort((a, b) => b.imdbRating - a.imdbRating) // 默认按添加时间排序 default: return [].concat(movies).sort((a, b) => a.addedAt - b.addedAt) } }
即使原数组顺序被意外修改,也能通过时间戳保证添加顺序。
- 排查
orderBy状态异常:添加日志监控orderBy变化,确认是否被误修改:
useEffect(() => { console.log('当前排序规则:', orderBy); }, [orderBy]);
若发现orderBy被自动设为10-1,检查select组件是否存在交互bug或其他代码修改了该状态。
内容的提问来源于stack exchange,提问作者dharani
相关产品推荐
相关产品推荐

