Data fetched from Firebase using useSWR returns undefined

Viewed 1857

I am following a course where I am fetching data from Firebase using useSWR and using it to set the state. However when I try to console log the data, I get undefined and the screen shows loading. Is there any reason to this. I even copied the exact same code the instructor uses (except the API link).

import { useEffect, useState } from 'react';
import useSWR from 'swr';

function LastSalesPage() {
  const [sales, setSales] = useState();
  // const [isLoading, setIsLoading] = useState(false);

  const { data, error } = useSWR(
    'https://nextjs-2021-default-rtdb.firebaseio.com/sales.json'
  );

  console.log('Data:', data);

  useEffect(() => {
    if (data) {
      const transformedSales = [];

      for (const key in data) {
        transformedSales.push({
          id: key,
          username: data[key].username,
          volume: data[key].volume,
        });
      }

      setSales(transformedSales);
    }
  }, [data]);

  if (error) {
    return <p>Failed to load.</p>;
  }

  if (!data || !sales) {
    return <p>Loading...</p>;
  }

  return (
    <ul>
      {sales.map((sale) => (
        <li key={sale.id}>
          {sale.username} - ${sale.volume}
        </li>
      ))}
    </ul>
  );
}

export default LastSalesPage;
2 Answers

Accordingly to the official docs -

the useSWR hook accepts a key string and a fetcher function. key is a unique identifier of the data (normally the API URL) and will be passed to fetcher. fetcher can be any asynchronous function which returns the data, you can use the native fetch or tools like Axios.

So it seemns that you simply don't pass any fetcher there.

Try defining hook like so:

const fetcher = (url) => fetch(url).then((res) => res.json());

  const { data, error } = useSWR(
    'https://nextjs-2021-default-rtdb.firebaseio.com/sales.json',
    fetcher
  );

Alternatively you can wrap your app with <SWRConfig> and set fetcher globaly, that would be available for all children components within that wrapper/context. And I supposed this is exactly what you were lacking in your code and couldn't use the hook without explicitly passing a fetcher.

E.g.

function App () {
  return (
    <SWRConfig 
      value={{
        fetcher: (...args) => fetch(...args).then(res => res.json())
      }}
    >
      <Example />
    </SWRConfig>
  )
}

So with having this in place your code example would work without passing fetcher parameter and this is exactly why it is optional

  const { data : userData, error: errorUserData } = useSWR(
    'https://nextjs-2021-default-rtdb.firebaseio.com/sales.json'
  );

And your full file (working, tested by me):

import { useEffect, useState } from 'react';
import useSWR from 'swr';

function LastSalesPage() {
  const [sales, setSales] = useState();
  // const [isLoading, setIsLoading] = useState(false);

  const { data: userData, error: userDataError } = useSWR(
    'https://nextjs-2021-default-rtdb.firebaseio.com/sales.json'
  );



  if (userDataError) {
    return <p>Failed to load.</p>;
  }

  if (!userData) {
    return <p>Loading...</p>;
  }
  if (userData){
  let transformedSales = [];

      for (const key in userData) {
        transformedSales.push({
          id: key,
          username: userData[key].username,
          volume: userData[key].volume,
        });
  }
  console.log(userData, transformedSales)
  let sales = transformedSales
  return (
    <ul>
      {sales.map((sale) => (
        <li key={sale.id}>
          {sale.username} - ${sale.volume}
        </li>
      ))}
    </ul>
  );
  }
}

export default LastSalesPage;

P.S don't use useEffect() hook (react hook) for data fetching, useSWR works perfect for this purpose.

P.S (2) you don't need fetcher to fetch data with no special params, so just = useSWR('/api/path')

Explanation about fetcher: if you check official docs, fetcher is optional param. "The fetcher here is an async function that accepts the key of SWR, and returns the data" - from here. I can't really explain why your code with fetcher works, but I shared your modified code with clear logic.

Related