Skip to content
Advertisement

TypeError: Cannot read property ‘title’ and map of undefined React Hooks props problem

I have a Json file to be fetched. I fetched the data and can get the data in the console from App.js. But when I pass the data as props to my child component, it gives me an empty array and does not display the items. What could be the mistake here ? My json data and components are below

App.js

import React, { useEffect, useState } from "react";
import logo from "./logo.svg";
import "./App.css";
import ProcessContainer from "./components/AdoptionProcess/ProcessContainer";


function App() {
  const [adoptionProcess, setAdoptionProcess] = useState([])

  async function fetchAsync () {
    let response = await fetch('./data.json');
    let data = await response.json();
    return data;
  }
  
  fetchAsync()
      .then(data => setAdoptionProcess(data))

      useEffect(() => {
        fetchAsync()
      },[])

  return (
    <div className="App">
    <ProcessContainer adoptionProcess={adoptionProcess}/>
    </div>
  );
}

export default App;
ProcessContainer.js

import React, { useEffect, useState } from "react";
import ProcessItems from "./ProcessItems";
import { Container, Row, Col } from "react-bootstrap";
import 'bootstrap/dist/css/bootstrap.min.css';

const ProcessContainer = ({adoptionProcess}) => {
  console.log(adoptionProcess)  // -> gives and empty array here


  return (
    <Container>
      <Row className="adoptionContainer py-5">
        <Col sm={12}>
          <h1>{adoptionProcess && adoptionProcess.adoptionProcessTitle.title}</h1>
          <Row className="mt-5 items">
            {adoptionProcess && adoptionProcess.adoptionProcessItems.map((process) => (
              <ProcessItems 
                img={process.img}
                text={process.text}
                firstDescription={process.firstDescription}
                secondDescription={process.secondDescription}
              />
            ))}
          </Row>
        </Col>
      </Row>
    </Container>
  );
};

export default ProcessContainer;
ProcessItems.js

import React from "react";
import { Col } from "react-bootstrap";
import "./AdoptionProcess.css";

const ProcessItems = ({
  img,
  text,
  firstDescription,
  secondDescription
}) => {
  return (
    <Col lg={4} className="mb-5">
      <img src={img} alt="img" className="mb-3" />
      <p>{text}</p>
      <span>{firstDescription}</span> <br />
      <span>{secondDescription}</span>
    </Col>
  );
};

export default ProcessItems;
data.json

{
    "adoptionProcessItems": [
          {
            "id": 1,
            "img": "https://i.pinimg.com/736x/2e/23/d3/2e23d3827c8293c27cea544a8acbcd59.jpg",
            "text": "Find Your Pet",
            "firstDescription": "Lorem Ipsum Lorem Ipsum Lorem",
            "secondDescription": "Lorem Ipsum Lorem Ipsum Lorem"
          },
          {
            "id": 2,
            "img": "https://i.pinimg.com/736x/5f/80/85/5f80854fd1475958717a19e345695942.jpg",
            "text": "Find Your Pet",
            "firstDescription": "Lorem Ipsum Lorem Ipsum Lorem",
            "secondDescription": "Lorem Ipsum Lorem Ipsum Lorem"
          },
          {
            "id": 3,
            "img": "https://i.pinimg.com/736x/2e/23/d3/2e23d3827c8293c27cea544a8acbcd59.jpg",
            "text": "Find Your Pet",
            "firstDescription": "Lorem Ipsum Lorem Ipsum Lorem",
            "secondDescription": "Lorem Ipsum Lorem Ipsum Lorem"
          }
    ],
    "adoptionProcessTitle" : {
        "title" : "Pet Adoption Process"
      }
  }

the visual will be like this enter image description here

Advertisement

Answer

There are multiple mistakes, you have in your code.

  1. Data returns object so please add initial state as an object.
const [adoptionProcess, setAdoptionProcess] = useState({});
  1. Adding async operation required loading flag
useEffect(() => {
    (async () => {
      const data = await fetchAsync();
      setAdoptionProcess(data);
      setLoading(false);
    })();
  }, []);

Why do I need to add a loading flag?

Because when your async operation is going on your processContainer will get the {} empty object as your adoption process and now you are accessing the adoptionProcess.adoptionProcessTitle.title but the adoptionProcess is empty so you are accessing the undefined of title and you got the same error in your response.

After the async operations are finished the state will be set and it causes the rerender and your processContainer will get your data.json data and you will get the results.

so the problem is your initial state and you can handle it using loading flag

Please check this https://codesandbox.io/s/eager-jackson-m8odq?file=/src/App.js

Advertisement