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 !

2
  • Does this answer your question? Infinite loop in useEffect Commented May 6, 2022 at 8: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. Commented May 6, 2022 at 8:11

1 Answer 1

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;
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks a lot for your answer it's works perfectly ! With your example of [0, 1] === [0, 1] make total sense !

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.