Home > Software design >  synchronising JSON useEffect
synchronising JSON useEffect

Time:10-16

I have a local json file (data.json) and I want to pull data into my React App. Console logs work fine, but the data is not available in the React state to work with.

I've been following this blog. Accordingly, I have data.json under the public folder of the project.

Here is the code:

App.js

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

function App() {
  const [data, setData] = useState([]);

  const getData = () => {
    fetch("data.json", {
      headers: {
        "Content-Type": "application/json",
        Accept: "application/json",
      },
    })
      .then(function (response) {
        console.log("response", response);
        return response.json();
      })
      .then(function (myJson) {
        console.log("myjson", myJson);
        setData(myJson);
      });
  };

  useEffect(() => {
    getData();
    console.log("data is", data);
  }, []);

  return (
    <div>
      {data && data.length > 0 && data.map((item) => <p>{item.text}</p>)}
    </div>
  );
}

export default App;

Console.log outputs the following:

data is []
data is []
response Response {type: 'basic', url: 'http://localhost:3000/data.json', redirected: false, status: 200, ok: true, …}
Response {type: 'basic', url: 'http://localhost:3000/data.json', redirected: false, status: 200, ok: true, …}
myjson {1: {…}, 2: {…}}
  1: {text: 'first item', done: true}
  2: {text: 'second item', done: false}
  [[Prototype]]: Object
myjson {1: {…}, 2: {…}}
  1: {text: 'first item', done: true}
  2: {text: 'second item', done: false}
  [[Prototype]]: Object

I have read several questions / answers on stackoverflow, and I understand that the data is asynchronous but I don't get how to call it only when it's ready. I've tried separate useEffect calls, but to no avail.

CodePudding user response:

You can try using the useEffect hook with an empty dependency array. This will make sure that the fetch request is only made once, when the component mounts.

You can also try using the useEffect hook with the data dependency. This will make sure that the fetch request is made every time the data changes.

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

function App() {
  const [data, setData] = useState([]);

  const getData = () => {
    fetch("data.json", {
      headers: {
        "Content-Type": "application/json",
        Accept: "application/json",
      },
    })
      .then(function (response) {
        console.log("response", response);
        return response.json();
      })
      .then(function (myJson) {
        console.log("myjson", myJson);
        setData(myJson);
      });
  };

  useEffect(() => {
    getData();
  }, []);

  return (
    <div>
      {data && data.length > 0 && data.map((item) => <p>{item.text}</p>)}
    </div>
  );
}

export default App;

CodePudding user response:

It's just the return, that's not working in your code:

You receive an object in your console.log here:

myjson {1: {…}, 2: {…}}
  1: {text: 'first item', done: true}
  2: {text: 'second item', done: false}

but you try to test on data. in the return, which will always yield undefined.

You could test on the Object.values and use those for your mapping to get the desired result:

return (
    <div>
      {data && Object.values(data).length > 0 && Object.values(data).map((item) => <p>{item.text}</p>)}
    </div>
  );
  • Related