1

Like the title says useFetch custom hook that I made is returning data twice, what do I mean by that. Well when I console.log the data that I fetched there are two outputs, one of them has value null, and the other is the data that I want, and because there is data with null value, that is a problem since I can't fulfill the table with the data I want. Here is the code:

import { useState, useEffect } from "react";
import axios from "axios";
const useFetch = (url) => {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);

  useEffect(() => {
    setLoading(true);
    axios
      .get(url)
      .then((response) => {
        setData(response.data);
      })
      .catch((err) => {
        setError(err);
      })
      .finally(() => {
        setLoading(false);
      });
  }, [url]);

  return { data, loading, error };
};

export default useFetch;

And this is where I want to use the data I fetched:

import React from "react";
import Table from "@mui/material/Table";
import TableBody from "@mui/material/TableBody";
import TableCell from "@mui/material/TableCell";
import TableContainer from "@mui/material/TableContainer";
import TableHead from "@mui/material/TableHead";
import TableRow from "@mui/material/TableRow";
import useFetch from "./custom_hooks/useFetch";

const TableComponent = () => {
  const { data, loading, error } = useFetch(
    "https://gorest.co.in/public/v1/users?page=1"
  );

  if (loading) return <h1> LOADING...</h1>;

  if (error) console.log(error);

  console.log(data);

  return (
    <TableContainer>
      <Table>
        <TableHead>
          <TableRow>
            <TableCell>User Names</TableCell>
            <TableCell align="right">Email</TableCell>
            <TableCell align="right">Status</TableCell>
            <TableCell align="right">Gender</TableCell>
            <TableCell align="right">ID</TableCell>
          </TableRow>
        </TableHead>
        <TableBody>
          {data.data.map((user) => {
            return (
              <TableRow>
                <TableCell>{user.name}</TableCell>
              </TableRow>
            );
          })}
        </TableBody>
      </Table>
    </TableContainer>
  );
};

export default TableComponent;

When I refresh the page, there is an error 'Data is null', how to fix this?

ahmedskulj10
  • 381
  • 1
  • 15
  • 1
    can you add the logs to the description of you question , – Zouhair Dre Oct 04 '21 at 12:20
  • 1
    Well, that's to be expected, no? You initialize `data` in `useFetch` hook as `null`. Then, when your `TableComponent` is first rendered, the `useEffect` inside `useFetch` fires, at which point the data is (asynchronously) loaded. When the data is loaded, your `TableComponent` sees there is new `data` available, and thus re-renders itself. This is how React works. Either initialize your `data` with something other than `null`, or just check if `data !== null` before trying to render it. – nbokmans Oct 04 '21 at 12:20

1 Answers1

3

Your hook doesn't manage its internal state quite properly. (For instance, if a fetch errors, it never un-errors.) Also, if you change the URL, the hook could end up having data for the wrong URL due to a previous effect finishing first.

As such, maybe it'd be better to just look at whether you do have data instead of trusting the other flags to be correct:

const { data, loading, error } = useFetch("https://gorest.co.in/public/v1/users?page=1");
if(error) return <>Error: {String(error)}</>;
if(!data) return <h1>LOADING...</h1>;

Beyond that, you might want to look into a library that does the state management, caching, etc. correctly for you; at the time of writing I'd recommend swr or react-query...

AKX
  • 152,115
  • 15
  • 115
  • 172