5

I'm trying to display a <Loading> component till the DATA fetch is a success,
after which I display a Child component. I don't understand why the state is not updated...

How can I handle this?

I'm using react-admin but it doesn't really matter I guess.
I have a <Dashboard> which should pass defibs (Array) to the <DefibsCard>.

When I log defibs in <DefibsCard> I have an empty array. Thanks !

const Dashboard = () => {
  const dataProvider = useDataProvider();
  const [loading, setLoading] = useState(true);
  const [defibs, setDefibs] = useState([]);

  const fetchDefibs = () => {
    dataProvider.getList('defibrillateurs', {
      filters: {}, sort: {field: 'id', order: 'ASC'}, pagination: {page: 1, perPage: 10}
    }).then((response) => {
      setDefibs(response.defibs);
      setLoading(false);
    })
  }

  useEffect(() => {
    fetchDefibs();
    console.log(loading)
  }, [])

  const classes = useStyles();

  return (!defibs 
    ? <Loading />
    : <div className={classes.flex}>
        <div className={classes.leftCol}>
          <div className={classes.flexColumn}>
            // ...
            <div className={classes.flex}>
              <DefibsCard defibs={defibs}/> // Child component
              <AlertsCard />
            </div>
          </div>
        </div>
        // ...
      </div>);
};
MwamiTovi
  • 2,425
  • 17
  • 25
karamasov
  • 51
  • 1
  • 2

4 Answers4

4

I do have experience with old react
So i can suggest you these chanfes

useEffect(() => {
    setLoading(true); // here 
    fetchDefibs();
    console.log(loading)
}, [])

Then

const fetchDefibs = () => {
    dataProvider.getList('defibrillateurs', {
        filters: {},
        sort: {field: 'id', order: 'ASC'},
        pagination: { page: 1, perPage: 10 }
    }).then((response) => {
        setLoading(false);   // here 
        setDefibs(response.defibs)
        setLoading(false);
    }).catch( e =>         setLoading(false);)

}

then

return(
    {!loading ? <Loading />
    :
    <div className={classes.flex}>
        <div className={classes.leftCol}>
            <div className={classes.flexColumn}>
                <Card>
                    <CardHeader title="Welcome to the administration" />
                    <CardContent>Lorem ipsum sic dolor amet...</CardContent>
                </Card>
            ......
   }

As you are using { defibs && it will always be true as you have initialise it [] it will be only false if it is undefined or null and using defibs && defibs.length = 0 is not the best way as if database return array with 0 length [] then to you app will show loading

Rajan Lagah
  • 2,373
  • 1
  • 24
  • 40
0

I think the issue is you are using the wrong expression

!defibs always return false no matter defibs is empty array or a loaded array.

You should change the expression to defibs.length <= 0 to explicitly ask <Loading /> component to be rendered when defibs is empty

MarkoCen
  • 2,189
  • 13
  • 24
0

This lies more in how you initially define the defibs variable.
Let's look at this more closely...

const Dashboard = () => {
  // This is where the bug is...
- const [defibs, setDefibs] = useState([]);
  // !defibs === `false`
  // ![] or ![1,2,3,4] === `false`

  // Update this line as follows
+ const [defibs, setDefibs] = useState(null);
  // Initially !defibs, since !null === true, thus <Loading> is rendered
  // After the `useEffect`, state is actually updated...
  // And !defibs is false, since ![] === false, the <DefibsCard> is rendered

  //...the rest looks fine
};

That should give your <Dashboard> working logic to render the right component.

MwamiTovi
  • 2,425
  • 17
  • 25
0

For the functional component I think the best is useeffect

import { useEffect, useState } from 'react';
function FetchEmployeesByQuery({ query }) {
  const [employees, setEmployees] = useState([]);
  useEffect(() => {
    async function fetchEmployees() {
      const response = await fetch(
        `/employees?q=${encodeURIComponent(query)}`
      );
      const fetchedEmployees = await response.json(response);
      setEmployees(fetchedEmployees);
    }
    fetchEmployees();
  }, [query]);
  return (
    <div>
      {employees.map(name => <div>{name}</div>)}
    </div>
  );
}

Source: 5. Fetching data

quine9997
  • 685
  • 7
  • 13