React中currentMovie状态对象值无法更新问题排查
问题:React下拉菜单切换时currentMovie状态未更新
我尝试用React创建电影名称下拉菜单,希望切换选项时,通过选中值匹配movies数组中对象的id来更新currentMovie状态,但切换选项时currentMovie的值没变化,代码如下:
import { useState } from 'react'; import MovieComp from './Movie'; function ParentComp(props) { const [movies, setMovies] = useState( [ { id : 1 , name : "Under the Dome", pic : "https://static.tvmaze.com/uploads/images/medium_portrait/81/202627.jpg" }, { id : 2 , name : "Person of Interest", pic : "https://static.tvmaze.com/uploads/images/medium_portrait/163/407679.jpg" }, { id : 3 , name : "Bitten", pic : "https://static.tvmaze.com/uploads/images/medium_portrait/0/15.jpg" } ] ) const [currentMovie, setCurrentMovie] = useState( {id : "" , name : "", pic : "" } ) function createDropMenu() { return movies.map( item => { return <option key={item.id} value={item.id} > {item.name} </option> } ) } function updateMovie(e) { if (e.target.value === 0) { console.log("test") let selectedMovie = {id : "" , name : "", pic : "" }; let selectedMovieEntries = Object.entries(selectedMovie); selectedMovieEntries.map( entry => { setCurrentMovie( prev => ( {...prev, [ entry[0] ]: entry[1] } ) ); }) } else { console.log("test") let selectedMovie = movies.find( item => item.id === e.target.value ); let selectedMovieCopy = {}; selectedMovieCopy = {...selectedMovie}; let selectedMovieEntries = Object.entries(selectedMovieCopy); selectedMovieEntries.map( entry => { setCurrentMovie( prev => ( {...prev, [ entry[0] ]: entry[1] } ) ); }) } } return ( <div> <h3> Pick a movie: </h3> <select onChange={updateMovie}> <option value={0} ></option> {createDropMenu()} </select> <br/> <MovieComp name = {currentMovie.name} pic = {currentMovie.pic} /> </div> ); } export default ParentComp;
问题原因及修复方案
核心问题1:类型不匹配
select元素的value属性返回的是字符串类型,而你movies数组里的id是数字类型,所以item.id === e.target.value的比较永远不成立,无法找到对应的电影对象,自然无法更新currentMovie。
核心问题2:不必要的多次状态更新
你通过遍历对象属性多次调用setCurrentMovie,React的状态更新是批量处理的,多次调用会被合并,而且完全没必要逐个属性更新,直接一次性设置整个对象即可。
修复后的代码
import { useState } from 'react'; import MovieComp from './Movie'; function ParentComp(props) { const [movies, setMovies] = useState( [ { id : 1 , name : "Under the Dome", pic : "https://static.tvmaze.com/uploads/images/medium_portrait/81/202627.jpg" }, { id : 2 , name : "Person of Interest", pic : "https://static.tvmaze.com/uploads/images/medium_portrait/163/407679.jpg" }, { id : 3 , name : "Bitten", pic : "https://static.tvmaze.com/uploads/images/medium_portrait/0/15.jpg" } ] ) const [currentMovie, setCurrentMovie] = useState( {id : "" , name : "", pic : "" } ) function createDropMenu() { return movies.map( item => { return <option key={item.id} value={item.id} > {item.name} </option> } ) } function updateMovie(e) { // 将字符串类型的value转为数字 const selectedId = Number(e.target.value); if (selectedId === 0) { // 直接重置整个currentMovie对象 setCurrentMovie({ id: "", name: "", pic: "" }); } else { // 现在类型匹配,能正确找到对应的电影对象 const selectedMovie = movies.find(item => item.id === selectedId); // 增加判断,防止找不到对应id的情况 if (selectedMovie) { // 直接设置整个对象,无需逐个属性更新 setCurrentMovie(selectedMovie); } } } return ( <div> <h3> Pick a movie: </h3> <select onChange={updateMovie}> <option value={0} ></option> {createDropMenu()} </select> <br/> <MovieComp name={currentMovie.name} pic={currentMovie.pic} /> </div> ); } export default ParentComp;
关键修改点
- 使用
Number()将e.target.value转为数字,确保与movies中的id类型一致,让find方法能正确匹配。 - 移除循环遍历属性的逻辑,直接通过一次
setCurrentMovie设置整个对象,避免状态更新合并问题,代码更简洁。 - 增加
if (selectedMovie)判断,提升代码健壮性,防止出现找不到对应id的异常情况。
内容的提问来源于stack exchange,提问作者krissy lynn
相关产品推荐
相关产品推荐

