0

I am fairly new to react, I am developing a component that will get data from a local JSON file and output it on to a table component.

I am currently stuck on a loading screen, I am getting the following error, Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0

My first thoughts were that the JSON file was potentially broken, I have tested the JSON file using JSON lint and it is valid.

App.js

import React, { useEffect, useState, useMemo } from "react";
import './App.css';

import Search from './components/Search'
import TableHeader from './components/Header'
import Pagination from './components/Pagination'

import useFullPageLoader from "./hooks/useFullPageLoader";

import mockData from './MOCK_DATA.json';

function App() {
  const [details, setDetails] = useState([]);
  const [loader, showLoader, hideLoader] = useFullPageLoader();
  const [totalItems, setTotalItems] = useState(0);
  const [currentPage, setCurrentPage] = useState(1);
  const [search, setSearch] = useState("");
  const [sorting, setSorting] = useState({ field: "", order: "" });

  const ITEMS_PER_PAGE = 50;

  const headers = [
      { name: "id", field: "id", sortable: false },
      { name: "first_name", field: "first_name", sortable: true },
      { name: "last_name", field: "last_name", sortable: true },
      { name: "email", field: "email", sortable: false },
      { name: "gender", field: "gender", sortable: false },
      { name: "ip_address", field: "ip_address", sortable: false }
  ];

  useEffect(() => {
    const getData = () => {
      showLoader();

      fetch(mockData)
          .then(response => response.json())
          .then(json => {
            hideLoader();
            setDetails(json);
        });
    };

      getData();
    }, []);

  const detailsData = useMemo(() => {
      let computedDetails = details;

      if (search) {
          computedDetails = computedDetails.filter(
              detail =>
                  detail.first_name.toLowerCase().includes(search.toLowerCase()) ||
                  detail.last_name.toLowerCase().includes(search.toLowerCase())
          );
      }

      setTotalItems(computedDetails.length);

      //Sorting comments
      if (sorting.field) {
          const reversed = sorting.order === "asc" ? 1 : -1;
          computedDetails = computedDetails.sort(
              (a, b) =>
                  reversed * a[sorting.field].localeCompare(b[sorting.field])
          );
      }

      //Current Page slice
      return computedDetails.slice(
          (currentPage - 1) * ITEMS_PER_PAGE,
          (currentPage - 1) * ITEMS_PER_PAGE + ITEMS_PER_PAGE
      );
  }, [details, currentPage, search, sorting]);

  return (
    <div className="row w-100">
      <div className="col mb-3 col-12 text-center">
        <div className="row">
          <div className="col-md-6">
            <Pagination
                total={totalItems}
                itemsPerPage={ITEMS_PER_PAGE}
                currentPage={currentPage}
                onPageChange={page => setCurrentPage(page)}
            />
          </div>
          <div className="col-md-6 d-flex flex-row-reverse">
            <Search
                onSearch={value => {
                    setSearch(value);
                    setCurrentPage(1);
                }}
            />
          </div>
        </div>

        <table className="table table-striped">
          <TableHeader
              headers={headers}
              onSorting={(field, order) =>
                  setSorting({ field, order })
              }
          />
          <tbody>
              {detailsData.map(detail => (
                  <tr>
                      <th scope="row" key={detail.id}>
                          {detail.id}
                      </th>
                      <td>{detail.first_name}</td>
                      <td>{detail.last_name}</td>
                      <td>{detail.email}</td>
                      <td>{detail.gender}</td>
                      <td>{detail.ip_address}</td>
                  </tr>
              ))}
          </tbody>
        </table>
      </div>
      {loader}
    </div>
  );
};

export default App;

MOCK_DATA.json

[{"id":1,"first_name":"Felicdad","last_name":"McKimmie","email":"fmckimmie0@lycos.com","gender":"Agender","ip_address":"99.216.194.167"},
{"id":2,"first_name":"Reinald","last_name":"Capelen","email":"rcapelen1@e-recht24.de","gender":"Male","ip_address":"193.151.24.49"},
{"id":3,"first_name":"Francyne","last_name":"Sheers","email":"fsheers2@surveymonkey.com","gender":"Genderqueer","ip_address":"117.134.38.199"},
{"id":4,"first_name":"Luelle","last_name":"Reynold","email":"lreynold3@tumblr.com","gender":"Polygender","ip_address":"203.34.23.135"},
{"id":5,"first_name":"Ivy","last_name":"Perrottet","email":"iperrottet4@elpais.com","gender":"Bigender","ip_address":"106.12.116.189"},
{"id":6,"first_name":"Tobye","last_name":"Petyt","email":"tpetyt5@bbb.org","gender":"Polygender","ip_address":"225.146.16.182"},
{"id":7,"first_name":"Eliot","last_name":"Maginn","email":"emaginn6@state.tx.us","gender":"Bigender","ip_address":"193.19.188.237"},
{"id":8,"first_name":"Ciel","last_name":"Lucio","email":"clucio7@lulu.com","gender":"Polygender","ip_address":"249.65.61.1"},
{"id":9,"first_name":"Haslett","last_name":"Farris","email":"hfarris8@noaa.gov","gender":"Male","ip_address":"247.37.86.113"},
{"id":10,"first_name":"Sunshine","last_name":"Gascard","email":"sgascard9@netvibes.com","gender":"Non-binary","ip_address":"118.125.194.37"},
{"id":11,"first_name":"Dieter","last_name":"Marner","email":"dmarnera@springer.com","gender":"Female","ip_address":"212.250.147.88"},
{"id":12,"first_name":"Oliy","last_name":"Manicomb","email":"omanicombb@arizona.edu","gender":"Agender","ip_address":"166.17.214.135"},
{"id":13,"first_name":"Jacky","last_name":"Beidebeke","email":"jbeidebekec@wunderground.com","gender":"Female","ip_address":"75.17.95.9"},
{"id":14,"first_name":"Berton","last_name":"Juan","email":"bjuand@bandcamp.com","gender":"Bigender","ip_address":"254.215.187.1"},
{"id":15,"first_name":"Gerick","last_name":"Freezor","email":"gfreezore@vkontakte.ru","gender":"Agender","ip_address":"140.42.52.239"},
{"id":16,"first_name":"Adore","last_name":"Millichip","email":"amillichipf@php.net","gender":"Genderfluid","ip_address":"67.110.77.105"},
{"id":17,"first_name":"Clim","last_name":"Gribbon","email":"cgribbong@google.de","gender":"Female","ip_address":"109.101.93.221"},
{"id":18,"first_name":"Ozzy","last_name":"Harbert","email":"oharberth@yelp.com","gender":"Male","ip_address":"217.37.94.242"},
{"id":19,"first_name":"Zonnya","last_name":"Connock","email":"zconnocki@webnode.com","gender":"Genderfluid","ip_address":"112.216.14.43"},
{"id":20,"first_name":"Quincy","last_name":"Dorton","email":"qdortonj@jugem.jp","gender":"Genderqueer","ip_address":"112.2.53.222"}]
Luke
  • 29
  • 8
  • `fetch` takes a string url. When you feed it your JSON data it turns it into a string and attempts to request that HTML page, which of course doesn't exist so you get whatever 404 page your server serves unknown URLs. You can't parse HTML as JSON, so you get that error. – Jared Smith Mar 08 '21 at 21:18
  • Here are some ways to do it https://stackoverflow.com/questions/34944099/how-to-import-a-json-file-in-ecmascript-6 – Szabó Sebestyén Mar 08 '21 at 21:26

1 Answers1

2

fetch expects a URL in order to fetch data from some endpoint.

You've given it a JSON and it doesn't know what to do with it. If you want to use the fake data you could do something like this in your useEffect

const getData = () => {
    showLoader();

    Promise.resolve(mockData)
        .then(json => {
          hideLoader();
          setDetails(json);
      });
  };
Flagship1442
  • 1,688
  • 2
  • 6
  • 13