Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Updating React state (object array) and component rerenders, but display does not change until another state updates

I am updating a state array when a button is clicked. The component seems to be re-rendering (based on a console log and the react developer tools extension), and the updated array is logged in the console correctly – however, it won’t actually display on screen. It only displays when a different state is updated.

The goal is for the user to search a character name and receive a list of all characters with that name in the TMDB database (currently only for shows with the origin_country TR).

As the user starts typing the name of the character they’d like to search in the input area, the input state is updated on each change.
When the user hits clicks the search icon, getChars() is called, which fetches the credits for each show in the showIds array and, for each person in the credits, checks if their character name matches the input. If it does, they’re added to the characters array.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

However, while the characters array prints correctly and immediately in the console (and my component rerenders), the actual display does not change. It doesn’t change if I click search again either – it only displays the list on the screen if I type another letter.

Console screenshot

My code currently:

export default function CharSearch(){
    console.log("rendered")
    const [input, setInput] = React.useState("")
    const [showIds, setShowIds] = React.useState([])
    const [characters, setCharacters] = React.useState([])

   React.useEffect(()=>{
    let tempShows=[]
    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}`
        fetch (query)
        .then (result=>result.json())
        .then (data=>data.results.map(show => tempShows.push({name: show.original_name, id: show.id})))
    }
    setShowIds(tempShows)
   }, [])


    function getChars(){ 
        let tempChars = []

        const charFetch = async (value) =>{
            let result = await fetch (`https://api.themoviedb.org/3/tv/${value.id}/aggregate_credits?api_key=${API_KEY}`)
            let data = await result.json()
            data.cast.map((person) => {person.roles[0].character.startsWith(input) && 
                    tempChars.push({character: person.roles[0].character, name: person.name, show: value.name})})
        }
            
        for (let value = 0; value<showIds.length; value++){
            charFetch(showIds[value])       
        }

        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} played by {person.name} in {person.show}</p>
                    )
                })}
            </div>
        </div>
        </div>
    )
}

I’ve searched stack overflow and tried many things, including:

  • updating the character array for every character instead of setting it with the tempChars array
  • using the spread operator
  • using fetch .then instead of async await
  • clearing the input bar at the end of getChars()
  • instead of a for loop, mapping over showIds and fetching in the map

All of them displayed in the console but not on screen.

Does anyone have any ideas on what I’m doing wrong?

>Solution :

You need to wait for all the requests to finish and then collect the results.

Promise.all(Array.from({length: 78}, (_, i) => 
    fetch(`https://api.themoviedb.org/3/discover/tv?api_key=${API_KEY}&with_origin_country=TR&page=${i + 1}`).then(r => r.json())
        .then(data => data.results.map(show => ({name: show.original_name, id: show.id})))))
    .then(res => setShowIds(res.flat()))

The same goes for getChars.

async function getChars() { 
    // ...
    for (let value = 0; value<showIds.length; value++){
        await charFetch(showIds[value]);
    }
    setCharacters(tempChars);
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading