React对象数组State更新后组件重渲染但视图未同步问题求助
问题原因
- 异步请求未等待完成就更新State:
getChars函数中,循环调用异步的charFetch但没有等待所有请求完成就执行setCharacters(tempChars),此时tempChars还是空数组。后续异步请求完成后虽然会填充tempChars,但因为没有再次调用setCharacters更新State,React无法感知数组内容变化,自然不会更新视图。只有当inputState变化触发重渲染时,组件才会读取到已经被填充的tempChars(数组是引用类型),从而展示结果。 - 初始化
showIds的逻辑存在异步问题:useEffect中的循环发起多个fetch请求,但没有等待所有请求完成就调用setShowIds(tempShows),导致showIds初始为空数组,后续请求完成后tempShows被填充但State未更新,可能导致首次搜索时无数据。
解决方案
1. 修复getChars函数,等待所有异步请求完成
使用Promise.all收集所有异步请求的Promise,等待全部完成后再更新characters State,确保tempChars填充完成后再设置State:
2. 修复useEffect中的showIds初始化逻辑
同样用Promise.all等待所有剧集数据请求完成后再设置showIds,保证showIds能正确获取到所有剧集ID:
修改后的完整代码:
export default function CharSearch(){ console.log("rendered") const [input, setInput] = React.useState("") const [showIds, setShowIds] = React.useState([]) const [characters, setCharacters] = React.useState([]) React.useEffect(()=>{ const fetchShows = async () => { const promises = []; for (let pageNum = 1; pageNum < 79; pageNum++){ let query = `https://api.themoviedb.org/3/discover/tv?api_key=${API_KEY}&with_origin_country=TR&page=${pageNum}`; promises.push(fetch(query).then(res => res.json())); } // 等待所有请求完成 const allData = await Promise.all(promises); const tempShows = allData.flatMap(data => data.results.map(show => ({name: show.original_name, id: show.id})) ); setShowIds(tempShows); }; fetchShows(); }, []) const getChars = async () => { let tempChars = []; const charFetch = async (value) => { const result = await fetch(`https://api.themoviedb.org/3/tv/${value.id}/aggregate_credits?api_key=${API_KEY}`); const data = await result.json(); // 筛选符合条件的角色并添加到数组 const matchedChars = data.cast.filter(person => person.roles[0]?.character?.startsWith(input) ).map(person => ({ character: person.roles[0].character, name: person.name, show: value.name })); tempChars.push(...matchedChars); }; // 收集所有异步请求的Promise const promises = showIds.map(value => charFetch(value)); // 等待所有请求完成后再更新State await Promise.all(promises); setCharacters(tempChars); } return( <div className="character-search"> <h1>Character Search</h1> <div className="search" > <div className="search-inputs"> <input type="text" value={input || ""} placeholder="Search character" onChange={(e)=>setInput(e.target.value)} /> <div className="search-icon"> <SearchIcon onClick={getChars}/> </div> </div> <div> <h3>Characters</h3> {characters.map((person)=>{ return( <p key={`${person.name}-${person.character}`}>{person.character} played by {person.name} in {person.show}</p> ) })} </div> </div> </div> ) }
额外优化点:
- 给
map的key添加person.character,避免同一演员饰演多个角色时key重复 - 在筛选角色时添加可选链
?.,防止person.roles[0]或character为undefined导致报错
内容的提问来源于stack exchange,提问作者Kay
相关产品推荐
相关产品推荐

