Home > Back-end >  useEffect with if statement not working React
useEffect with if statement not working React

Time:10-14

I'm trying to set a value to id 'packageStatus' when the value of package is an empty string.. The error in the console says: Cannot read properties of null (reading 'children'). I've tried placing the if statement before and after getParent(), but it doesn't work. This is my database where you can se package under children:

{
  "parents": [
    {
      "id": 0,
      "name": "Anna",
      "adress": "Skatgatan 6",
      "children": [
        {
          "age": "2 månader",
          "package": ""
        }
      ]
    }
  ],
  "packages": [
    {
      "id": 0,
      "size": "Small strl: 44-50"
    },
    {
      "id": 1,
      "size": "MEDIUM strl: 50-56"
    },
    {
      "id": 2,
      "size": "Large strl: 56-62"
    }
  ]
}

Here is my React component:

import { Link } from 'react-router-dom';
import { useEffect, useState } from 'react';
import '../style/Welcome.css';
import Navbar from './Navbar';
import '../style/Button.css';

const Welcome = () => {
  const [parent, setParent] = useState(null);

  useEffect(() => {
    const getParent = async () => {
      const response = await fetch('http://localhost:3001/parents/0').then(
        (response) => response.json()
      );
      // update the state
      setParent(response);
    };
    getParent();
    //if() not working...
    // if (parent.children[0].package === "") {
    //     getParent();
    //     document.getElementById('packageStatus').innerHTML = 'inget klädpaket ännu';
    //   }
  }, []);

  return (
    <div className='flex flex-col bg-white h-full bg-opacity-80'>
      <Navbar />
      <div className='mt-8 space-y-8'>
        <div className='text-black text-4xl font-bold'>
          {parent && <h1>Välkommen {parent.name}!</h1>}
        </div>
        <div className='bg-white mx-8 shadow-lg py-4 rounded-lg'>
          {parent && (
            <div className='space-y-4 text-xl'>
              <div>
                <p>
                  Du har{' '}
                  <span className='font-bold'>{parent.children.length}</span>{' '}
                  barn registrerat
                </p>
                <p>
                  som är{' '}
                  <span className='font-bold'>{parent.children[0].age}</span>{' '}
                  gammalt.
                </p>
                <p>
                  och har{' '}
                  <span id='packageStatus' className='font-bold'>
                    {parent.children[0].package}
                  </span>
                  .
                </p>
              </div>
              <div>
                <p>Din registrerade adress är:</p>
                <p>{parent.adress}</p>
              </div>
              <p className='text-orange-300 underline'>
                Stämmer inte dina uppgifter?
              </p>
            </div>
          )}
        </div>
      </div>
      <div className='mt-auto p-4'>
        <button className='bg-orange-400 text-2xl rounded-lg px-16 py-2'>
          <Link to='/Select'>GÅ VIDARE</Link>
        </button>
      </div>
    </div>
  );
};

export default Welcome;

CodePudding user response:

React's state updates aren't immediate. Therefore, after calling getParent, parent is null. Only after the fetch request completes and React's state update complete, parent will not be null (if response is not null).

What you can do is set the parent in useEffect dependencies and first check if the parent is defined:

useEffect(() => {
    const getParent = async () => {
        const response = await fetch('http://localhost:3001/parents/0').then(
            (response) => response.json()
        );
        // update the state
        setParent(response);
    };
    getParent();

    if (parent && parent.children[0].package === "") {
        getParent();
        document.getElementById('packageStatus').innerHTML = 'inget klädpaket ännu';
    }
    // parent is in useEffect's dependency list
}, [parent]);

An even better solution would be to use a second useEffect and extract getParent function:

const getParent = async () => {
    const response = await fetch('http://localhost:3001/parents/0').then(
        (response) => response.json()
    );
    // update the state
    setParent(response);
};

useEffect(() => {
    getParent();
}, []);

useEffect(() => {
    if (parent && parent.children[0].package === "") {
        getParent();
        document.getElementById('packageStatus').innerHTML = 'inget klädpaket ännu';
    }
}, [parent]);
  • Related