Home > database >  My useEffect hook is never triggered, not even on first load
My useEffect hook is never triggered, not even on first load

Time:01-31

I have an issue where the useEffect() React hook in my small React app is never triggered.

When the app loads, it first goes to index.js, which then loads the Dungeon component.

So it does work in that sense.

You can see I have console.log() calls so I can see what is being hit and what is not.

So the app does load find at the beginng, no errors.

It does load the Dungeon component and I see the expected generationId being written out to the console.

The API endpoint works because I can test it successfully using Postman.

The problem is, it never hits the api, because the getGeneration function is never hit because useEffect is never triggered.

The error I get is:

Dungeon.js:15 Uncaught TypeError: Cannot read properties of undefined (reading 'data')

The error happens because data is never filled by the api.

So I know why I am getting the error, but I have no clue as to why useEffect is not being triggered.

Does anyone see anything wrong or bad?

Here is my index.js:

ReactDOM.render(
    <React.Fragment>
        <Dungeon generationId={id} />
    </React.Fragment>,
    document.getElementById('dungeon')
)

And here is the Dungeon Component:

import React, { useState, useEffect } from "react";
import axios from 'axios';

const Dungeon = ({ generationId }) => {

    const [generationDetails, setGenerationDetails] = useState();
    console.log("Dungeon Component entry :: generationId has a value of --> ", generationId);

    const getGeneration = async (id) => {
        console.log("getGeneration hit.");
        const data = await axios.get('api/generations/'   id);
        setGenerationDetails(data);
    }

    useEffect(() => {
        console.log("useEffect() triggered..but it's never triggered! ");
        getGeneration(generationId);
    }, []) // Empty so it gets called only once
    return (
        <div id="generation">
            <div>
                <div id="generationDescription">
                    <div>Title:{generationDetails.data.title}</div>
                    <div>Description: {generationDetails.data.description}</div>
                </div>
            </div>
        </div>
    );
}

export default Dungeon;

CodePudding user response:

Your error appears to be caused during mounting your component (adding it to the DOM tree), which occurs before the useEffect() is run.

The first call to your useEffect is invoked at a similar state to componentDidMount (subsequent calls are similar to componentDidUpdate). In your case, mounting the component includes displaying your title and description, and those values are dependent on having an object to grab them from.

There are at least three possible solutions:

  1. Add a default object in your useState().
const [generationDetails, setGenerationDetails] = useState({
  data: {
    description: '',
    title: 'Loading...',
  }
});
  1. Test that the object has been loaded before rendering your JSX.
    ...

    return (
     {!!generationDetails && (
        <div id="generation">
            <div>
                <div id="generationDescription">
                    <div>Title:{generationDetails.data.title}</div>
                    <div>Description: {generationDetails.data.description}</div>
                </div>
            </div>
        </div>
     )
   });
  1. Use optional chaining for each value (mentioned also by Ossama). The expressions will return undefined until your object is created, and the undefined values will not render.
<div>Title:{generationDetails?.data?.title}</div>
<div>Description: {generationDetails?.data?.description}</div>

CodePudding user response:

I suggest you to use Optional chaining (?.) and a default value in the return of component, example instead of {generationDetails.data.title} you must use {generationDetails?.data?.title | ""}

  •  Tags:  
  • Related