Home > front end >  React: data not loading after being fetched
React: data not loading after being fetched

Time:04-04

Using MUI and I have a Select component (a dropdown menu) whose options I want to populate using data from a fetch request. I store the data in the state with an array, named 'partners'. Initially, partners.map() did not work because partners was empty, so I was thinking that I should wait for the fetch to finish before rendering. And so this is my code with that in mind:

  const [partners, setPartners] = useState([]);
  React.useEffect(() => {
    fetch('http://localhost:3000/partners')
      .then((resp) => resp.json())
      .then((data) => setPartners(data));
    console.log(partners);
  }, []);

  if (!partners.length) {
    return <Typography>Loading...</Typography>;
  }
  return ( 
    <FormControl>
      <>
        <Select
          onChange={handleFormChange}
        >
          {partners.map(({ name }) => (
            <MenuItem value={name}>{name}</MenuItem>
          ))}
        </Select>
      </>
    </FormControl>
  )

But now, the page is just stuck on 'Loading...' and doesn't change. I've tried using !!!partners.length in the if statement too but it didn't seem to make a difference. The console.log(partners) statement in the useEffect just returns an empty array. Thing is, the data being fetched is most definitely not empty/null so I'm not sure what's going on. Is it possible that the console.log() is being run before the fetch or setPartners statements fully complete? Is partners even being changed? If so, how is it possible that the check for partners.length doesn't return True at any point in time?

EDIT: Fixed, see answer below

CodePudding user response:

Created this stackblitz for you https://stackblitz.com/edit/react-mui-5spdkt?file=Hello.js

The issue was that the object you were trying to set on setPartners was not the list, in my case for the cats api I need the result.data and like Cesare said your console log was on the wrong place

CodePudding user response:

  React.useEffect(() => {
fetch('http://localhost:3000/partners')
  .then((resp) => resp.json())
  .then((data) => setPartners(data));
console.log(partners);  <=== THIS IS EXECUTED AS SOON AS THE FETCH STARTS SO IT'S GONNA BE []
  }, []);

If you want to log fetched data, you need to log inside the last then. Remember to place a .catch(e => console.error(e)) or you won't catch any issue.

If you want to check partners which is a React state, you need to place console.log(partners) just inside the React Component function, before the return statement.

  const [partners, setPartners] = useState([]);
  React.useEffect(() => {
    fetch('http://localhost:3000/partners')
      .then((resp) => resp.json())
      .then((data) => { 
                       setPartners(data);
                       console.log("FETCHED DATA:", data); 
                      })
      .catch(e => console.error(e));
  }, []);

  console.log("RENDERING, PARTNERS:", partners)

  if (!partners.length) {
    return <Typography>Loading...</Typography>;
  }
  return ( 
    <FormControl>
      <>
        <Select
          onChange={handleFormChange}
        >
          {partners.map(({ name }) => (
            <MenuItem value={name}>{name}</MenuItem>
          ))}
        </Select>
      </>
    </FormControl>
  )

CodePudding user response:

Fixed, the issue was that the fetch was returning an object with the array as the value and not the array itself like I assumed so I think that was screwing things up. I just replaced setPartners(data) with setPartners(data[key]) where key is the key mapped to the value.

CodePudding user response:

You can try to avoid returning your FormControl component before fetcing complete, like this:

const [partners, setPartners] = useState();
const [loading, setLoading] = useState();
React.useEffect(() => {
setLoading(true);
fetch('http://localhost:3000/partners')
    .then((resp) => resp.json())
    .then((data) => setPartners(data))
    .then(setLoading(false));
console.log(partners);
}, []);

return ( 
<FormControl>
    {loading ? <Typography>Loading...</Typography>
    : <>
        <Select
        onChange={handleFormChange}
        >
        {partners.map(({ name }) => (
            <MenuItem value={name}>{name}</MenuItem>
        ))}
        </Select>
    </> 
}  
</FormControl>
)
  • Related