Home > OS >  Rendering Flask JSON response in ReactJs
Rendering Flask JSON response in ReactJs

Time:07-15

So, I've been struggling with this and couldn't really find a solution. I have a Flask backend that does some operations and returns a JSON response like so

server.py

from flask import Flask
from pyresparser import ResumeParser


app = Flask(__name__)

# Details API Route
@app.route("/details")
def details():
    resume_data = ResumeParser(r'D:\React\Candetect\backend\Uploaded_Resumes\OmkarResume.pdf').get_extracted_data()
    email = resume_data.get('email')    
    return {"Information":[email]}

if __name__== "__main__":
    app.run(debug=True)

Now, I'm getting this JSON response in App.jsx like so

  const [data, setData] = useState([])

  useEffect(() =>{
    fetch("/details").then(
      res => res.json()
    ).then(
      data => {
setData([data.Information])
        console.log(data)
      }
    )
  }, [])

And I'm trying to display it like so

<div>
      {(data.length === 0) ? (
        <p>Loading...</p>
      ) : (
        data.members.map((member, i) => (
          <h3 key={i}>{member.email}</h3>
        ))
      )}
    </div>
    </div>

The problem, the page loads up, I get loading... message displayed, then as the data is fetched I get this error TypeError: Cannot read properties of undefined (reading 'map')

For some reason it's considering it to be undefined.

This is what I get when I console.log(data)

{
    "Information": [
        "[email protected]"
    ]
}

CodePudding user response:

Effects let you run some code after rendering so that you can synchronize your component with some system outside of React

So basically, when your code will run for the first time, the code inside useEffect won't run. Using something like this, you can have a fallback render until your data loads.

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

A better solution would be to have a loading state that keeps track of the data that is being loaded.

const [data, setData] = useState([]);
const [loading, setLoading] = useState(true);

useEffect(() => {
    fetch("/details")
        .then((res) => res.json())
        .then((data) => {
            setData([data.Information]);
            setLoading(false);
            console.log(data);
        });
}, []);

if (loading && !data) {
    return <p>Loading...</p>;
}

if (!loading && !data) {
    return <p>Opps. Something`s wrong</p>;
}

return (
    <div>
        {data.members.map((member, i) => (
            <h3 key={i}>{member.email}</h3>
        ))}
    </div>
);

React v18 Fix

If you have the problem of useEffect firing twice, you can use something like to prevent it from doing that.

function App() {
  const effectRan = useRef(false);

  useEffect(() => {
    if (effectRan.current === true || process.env.NODE_ENV !== "development") {
      //
      //Code that should only run once !
      //
    }
    return () => (effectRan.current = true);
  }, []);

  return <p></p>;
}

export default App;

CodePudding user response:

So I ended up switching my code a bit. Here's what I did instead:

App.jsx

const [initialData, setInitialData] = useState([{}])

useEffect(() => {
    fetch('/details').then(
      response => response.json()
    ).then(data => setInitialData(data))
  }, []);

  return (
      <div>
        <h3>Hello {initialData.name}</h3>
      </div>
    </div>
  );

Then, in server.py

from flask import Flask

app = Flask(__name__)

# Details API Route
@app.route("/details")
def details():
    data = func(r'path\to\pdf').get_data()
    return {"email":data.get('email'),
            "mobile_number":data.get('mobile_number'),
            "name":data.get('name'),
    }

if __name__== "__main__":
    app.run(debug=True)
  • Related