0

I'm new to React Hook and I follow severals tutorials but I'm afraid I'm not understand everything.

I have two components with pretty much the same code but two differents behaviors and I don't understand why.

First component code :

function SO5Fixture(props) {

    const [gameweek, setGameWeek] = useState(0)

    const previousGWClick = () => {
        console.log("previousGW from " + gameweek)
        setGameWeek(gameweek - 1)        
    }

    const nextGWClick = () => {
        console.log("nextGW from " + gameweek)
        setGameWeek(gameweek + 1)
    }

    useEffect(() => {
        console.log("so5fixture useEffect")
        getGameWeekInfos()
      }, [gameweek])

    const getGameWeekInfos = async() => {
        console.log("getGameWeekInfos")
        var so5Fixture = await APISorare.getSo5Fixture(gameweek)
        setGameWeek(so5Fixture['data']['so5fixture_game_week'])
    }

    return (
        <div>
            <Container>
            ...
            </Container>
        </div>
    );
}
export default SO5Fixture;

Second component :

import React, { useEffect, useState } from "react";
import { Container, Row, Col, Button, ButtonGroup, Card, Alert } from "react-bootstrap";
import { LinkContainer } from 'react-router-bootstrap'
import APISorare from "../../utils/APISorare";


function SO5Games(props) {

    const [games, setGames] = useState([])

    useEffect(() => {
        console.log("so5Games useEffect")
        getGames()
      }, [games]) 

    const getGames = async() => {
        console.log("getGames : " + props.gameWeek)
        var so5Games = await APISorare.getSo5Games(props.gameWeek)
        setGames(so5Games['data'])
    }

    return (
        <div>
            {
                games.map( (game, idx) => (
                    <Alert key={idx} variant="secondary">
                        <Row>
                            <Col md={4}>{game['game_date']}</Col>
                            <Col md={8}>{game['home_team_name']} {game['home_team_score']}-{game['away_team_score']} {game['away_team_name']}</Col>
                        </Row>
                    </Alert>
                ))
            }
        </div>
    );
}

export default SO5Games;

In my console log, I find this :

so5fixture useEffect
SO5Fixture.js:28 getGameWeekInfos
APISorare.js:24 APISorare : getSo5Fixture
SO5Games.js:12 so5Games useEffect
SO5Games.js:17 getGames : 262
APISorare.js:33 APISorare : getSo5Games
SO5Fixture.js:23 so5fixture useEffect
SO5Fixture.js:28 getGameWeekInfos
APISorare.js:24 APISorare : getSo5Fixture
SO5Games.js:12 so5Games useEffect
SO5Games.js:17 getGames : 262
APISorare.js:33 APISorare : getSo5Games
SO5Games.js:12 so5Games useEffect
SO5Games.js:17 getGames : 262
APISorare.js:33 APISorare : getSo5Games
SO5Games.js:12 so5Games useEffect
SO5Games.js:17 getGames : 262
.........

I don't understand why my component "so5Games" re-render over and over whereas the so5Fixture component update just 2 twice (which is what I attempt because first call API with 0 and then with a real parameter) ?

Could you please help me to understand ?

Thanks a lot !

skyboyer
  • 22,209
  • 7
  • 57
  • 64
Sylvain
  • 13
  • 2
  • Does this answer your question? [Infinite loop in useEffect](https://stackoverflow.com/questions/53070970/infinite-loop-in-useeffect) – lawrence-witt May 06 '22 at 08:09
  • Essentially, it's the difference between passing primitive and reference values. One effect sets the state with a new array, which triggers the effect endlessly since arrays have different reference value. The other sets it with a primitive number, which only triggers the effect when the numerical value has actually changed. – lawrence-witt May 06 '22 at 08:11

1 Answers1

1

SO5Games re-renders indefinitely because the state variable is an array, remember that [0, 1] === [0, 1] will return false (because there are two distincts objects), whereas 0 === 0 will return true

Basically I would rewrite your components like this :

function SO5Fixture(props) {
    const [gameweek, setGameWeek] = useState(0)

    const previousGWClick = () => fetchGameWeekInfos(gameweek - 1)        
    const nextGWClick = () => fetchGameWeekInfos(gameweek + 1)

    // fetch game week infos on initial render
    useEffect(() => fetchGameWeekInfos(gameweek), [])

    const fetchGameWeekInfos = async (week) => {
        console.log("fetchGameWeekInfos")
        var so5Fixture = await APISorare.getSo5Fixture(week)
        setGameWeek(so5Fixture['data']['so5fixture_game_week'])
    }

    return (
        <div>
            <Container>
            ...
            </Container>
        </div>
    );
}
export default SO5Fixture;
function SO5Games(props) {
    const [games, setGames] = useState([])

    // load the games each time props.gameWeek is updated
    useEffect(() => {
        console.log("so5Games useEffect")
        fetchGames()
    }, [props.gameWeek]) 

    const fetchGames = async () => {
        console.log("getGames : " + props.gameWeek)
        var so5Games = await APISorare.getSo5Games(props.gameWeek)
        setGames(so5Games['data'])
    }

    return (...);
}

export default SO5Games;
Olivier Boissé
  • 15,834
  • 6
  • 38
  • 56
  • Thanks a lot for your answer it's works perfectly ! With your example of [0, 1] === [0, 1] make total sense ! – Sylvain May 06 '22 at 09:10