0

I am trying to create a simple Next.js page with the data fetched from backend. For fetching I am using useSWR.

If I refresh the page or open it for the first time after running dev, I get a TypeScript error because the data.results (fetched object's data) object is not defined. Which made me believe that either the API is not working or the fetching functions are wrongly configured. Yet both of these are not the case.

If I comment the 2 lines that have the fetched object (data.results), and refresh from browser, I can see an empty page, no surprises there. After that point if I uncomment console.log(data.results[1].name) and save the changes I can see the product's name in the browser console. Same goes for the second mention of data.results. So clearly, data fetching works because I can see the data in some situations. In this state, if I click the homepage button, then click the Prods button in the homepage to come back, it still works. It shows the data in console and also in the page. So as long as I don't refresh the the page it works.

And after that(without commenting those 2 lines), if I refresh the page from the browser, I get the TypeError again.

Screenshot of TypeScript Error

Before useSWR I tried, useEffect and useState for the same purpose but the same thing happened. I also used axiom but nothing changed. In conclusion, I am unable to create a simple page with the contents fetched from backend no matter how hard I tried. I feel like I am missing a fundamental knowledge. Before asking this question I went through pages of documentation but nothing.

In the code below, I try to render a button to homepage and the name of the second product. I have comments near the 2 lines that I mentioned above that uses data.results. In the index.js there is only a button that links to this Prods page.

import React, { useEffect, useState } from 'react';
import useSWR from 'swr'
import Link from "next/link"
import {Button} from '@mantine/core';

const fetcher = async (url, headers) => await fetch(url, {'method': 'GET', headers}).then(res => res.json())
function Prods() {
  const product_url = 'http://127.0.0.1:8000/api/product/'
  const headers = {
          'Content-type': 'application/json',
          'Authorization': `Token 9824eda0dd38b631b4aedf192899651cba91be53`
        }
  const { data, error } = useSWR([product_url, headers], fetcher)

  console.log(data.results[1].name) //if commented, refreshed and then uncommented it works.
  return (
    <div>
      <Link href="/" passHref>
        <Button className = "m-1">
          Homepage
        </Button>
      </Link>
      {/* {data.results[1].name} //if commented, refreshed and then uncommented it works. */}
    </div>
  )
}

export default Prods
juliomalves
  • 42,130
  • 20
  • 150
  • 146
Yasir Aydın
  • 5
  • 1
  • 2

2 Answers2

1

Have you tried server side rendering for this purpose? If you fetch data from backend, getServerSideProps is the right place to do that in a Next application.

import { GetServerSideProps } from "next";

...

export const getServerSideProps: GetServerSideProps = async (ctx) => {
  const fetcher = async (url, headers) => await fetch(url, {'method': 'GET', headers}).then(res => res.json())

  const product_url = 'http://127.0.0.1:8000/api/product/'
  const headers = {
          'Content-type': 'application/json',
          'Authorization': `Token 9824eda0dd38b631b4aedf192899651cba91be53`
        }
  const { data, error } = useSWR([product_url, headers], fetcher)
  console.log(data.results[1].name)

  return {
    props: {}
  }
}

export default Prods

You will not see console output on the console tab of your browser, instead watch your IDE terminal.

Alternatively, I would do it like below

import useSWR from 'swr'
import Link from "next/link"
import {Button} from '@mantine/core';

function Prods() {
  const fetcher = async (url, headers) => await fetch(url, {'method': 'GET', headers}).then(res => res.json())
  const product_url = 'http://127.0.0.1:8000/api/product/'
  const headers = {
          'Content-type': 'application/json',
          'Authorization': `Token 9824eda0dd38b631b4aedf192899651cba91be53`
  const { data, error } = useSWR([product_url, headers], fetcher)

  if (error) {
    return(<p>Loading failed...</p>);
  }

  if (!data) {
    return(<h1>Loading...</h1>);
  }

  return (
    <div>
      <Link href="/" passHref>
      <Button className = "m-1">
        Homepage
      </Button>
      </Link>
      {data.results[1].name}
    </div>
  );
}

export default Prods

or

import useSWR from 'swr'
import Link from "next/link"
import {Button} from '@mantine/core';

function Prods() {
  const fetcher = async (url, headers) => await fetch(url, {'method': 'GET', headers}).then(res => res.json())
  const product_url = 'http://127.0.0.1:8000/api/product/'
  const headers = {
          'Content-type': 'application/json',
          'Authorization': `Token 9824eda0dd38b631b4aedf192899651cba91be53`
  const { data, error } = useSWR([product_url, headers], fetcher)

  let pageContent;

  if (error) {
    pageContent = (<p>Loading failed...</p>);
  }
  else if (!data) {
    pageContent = (<h1>Loading...</h1>);
  }
  else {
    pageContent = (<p>data.results[1].name</p>);
  }

  return (
    <div>
      <Link href="/" passHref>
      <Button className = "m-1">
        Homepage
      </Button>
      </Link>
      {pageContent}
    </div>
  );
}

export default Prods
Ahmet Firat Keler
  • 2,603
  • 2
  • 11
  • 22
  • Thank you for your help. Interestingly, only lines of code to fix the error were: `if(error) { return(

    Loading failed...

    );} if (!data) { return(

    Loading...

    );}`. I've tried every alternative you mentioned and all of them worked until I deleted these if statements. I am not sure why it doesn't work if I don't validate the data with these ifs but it works with them for sure.
    – Yasir Aydın Apr 10 '22 at 07:45
  • Page is getting rendered before data is ready and it throws an error. Using those ifs, we make sure we do not try to render api related data before it's ready. – Ahmet Firat Keler Apr 10 '22 at 09:15
0

strong textcheckout this image to have solution

just add ? mark after data this will check weather data is present or not

<div>
  <h1>{data?.results[1].name}</h1>
  <div>
    <p>{post?.id}</p>
    <p>{post?.body}</p>
  </div>
</div>
Ameer
  • 1
  • 1
  • First, it's not helpful at all to post images of code. Second, where does the additional code come from and how is it helpful for answering the question? – JSON Derulo Apr 11 '23 at 10:12