You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React对象数组State更新后组件重渲染但视图未同步问题求助

问题原因

  1. 异步请求未等待完成就更新State:getChars函数中,循环调用异步的charFetch但没有等待所有请求完成就执行setCharacters(tempChars),此时tempChars还是空数组。后续异步请求完成后虽然会填充tempChars,但因为没有再次调用setCharacters更新State,React无法感知数组内容变化,自然不会更新视图。只有当input State变化触发重渲染时,组件才会读取到已经被填充的tempChars(数组是引用类型),从而展示结果。
  2. 初始化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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 17:15:54