Home > Software design >  React.js useState function passed as a parameter doesn't rerender its component
React.js useState function passed as a parameter doesn't rerender its component

Time:11-10

So what I'm trying to do is to have a component that renders a list of games.

The component calls the function ApiMMO.getGamesFromTo() from a separate script passing the (response)=>{setGameList(response)} as a parameter. This separated scripts does a request and uses the function passed as parameter to change the component's state. The script does the job and the console logs confirm that the gameList changed but the component doesn't rerender.

The way I know the component didn't rerender is because the GameCard component prints its props when mounted.

So here's the code:

function GameLibrary(){
    const [gameList, setGameList] = React.useState([]);
    const [gamesPerPage, setGamesPerPage] = React.useState(20);
    const [pageIndex, setPageIndex] = React.useState(1);

    // setgameList(ApiMMO.getGamesFromTo( gamesPerPage, pageIndex))

    React.useEffect(() => {
        ApiMMO.getGamesFromTo( gamesPerPage, pageIndex, ((response)=>{setGameList(response)}))
      }, [])

    React.useEffect(()=> {
        console.log('gameList changed: ');
        console.log(gameList);
    },[gameList])

    return(
        <div>
            { gameList.length > 0 ? (
                gameList.map(item => {
                <GameCard game={item}/>
            })) : (
                <GameCard game={'no prop'}/>
            ) }
        </div>
    );
}

EDIT:

Here's the ApiMMO.getGamesFromTo() code:

function getGamesFromTo(numPerPage, page, callback){
    let options = {
        method: 'GET',
        url: 'https://mmo-games.p.rapidapi.com/games',
        headers: {
          'x-rapidapi-host': 'mmo-games.p.rapidapi.com',
          'x-rapidapi-key': rapidapiUserKey
        }
      };

    axios.request(options).then(function (response) {

        let from = (page - 1) * numPerPage;
        let to = page * numPerPage;
        let pageArray = response.data.slice(from, to)
        console.log("REQUEST RESULT: "   pageArray)
        callback(pageArray)
        return pageArray;

    }).catch(function (error) {
        console.error(error);
    });
}

CodePudding user response:

You have to return some value on the map, or else remove the braces {}

Replace this:

return(
        <div>
            { gameList.length > 0 ? (
                gameList.map(item => {
                <GameCard game={item}/>
            })) : (
                <GameCard game={'no prop'}/>
            ) }
        </div>
    );

By this:

return(
    <div>
        { gameList.length > 0 ? (
            gameList.map(item => 
             <GameCard game={item}/>
        )) : (
            <GameCard game={'no prop'}/>
        ) }
    </div>
    );

Or this:

return(
        <div>
            { gameList.length > 0 ? (
                gameList.map(item => {
                 return <GameCard game={item}/>
            })) : (
                <GameCard game={'no prop'}/>
            ) }
        </div>
        );

CodePudding user response:

Can you change getGamesFromTo() so it doesn't need the callback and just returns the response?

Then in your useEffect you could just have:

React.useEffect(() => {
        setGameList(ApiMMO.getGamesFromTo(gamesPerPage, pageIndex))
}, [setGameList])
  • Related