Smlok
Smlok

Reputation: 658

Passing axios fetched prop from Parent to Child returns "TypeError: Cannot read property 'x' of undefined"

I know this question has been asked already, but the various answers provided just don't seem to work in my case.

Parent component

import axios from "axios";
import { useEffect, useState } from "react";
import Child from "../../components/fragments/Child";

// Fetches data with no errors
export default function Parent() {
  const [post, setPost] = useState([]);

  useEffect(() => {
    const fetchPost = async () => {
      await axios.get("http://localhost:xxxxx").then((res) => {
        setPost(res.data);
      });
    };
    fetchPost();
  }, []);

  return (
    <>
      <Child post={post} />
    </>
  );
}

Child Component

export default function Child({ post }) {
    return (
        <>
        {console.log(post)}
        {/* Sometimes returns an error because axios hasn't finished fetching */}
        </>
    );
  }

The Parent fetches the data from server with no errors. However, when I pass the data to the Child it sometimes throws "TypeError: Cannot read property 'post' of undefined". That breaks the whole application since the Child is trying to access post prop which is still in its initial empty array state before the data is fetched with axios.

Something like ComponentDidMount() does not work because the component maybe has mounted but the data is still being fetched by axios.

What is the best way to get around this problem? How can I always have the post data in Child passed by the Parent and avoid the "TypeError:..." screen of failure when trying to access the prop?

Upvotes: 1

Views: 862

Answers (1)

Drew Reese
Drew Reese

Reputation: 203333

Seems you are at some point updating the post state to be undefined and then accessing it in the child. You can conditionally render the Child component if post is undefined/falsey for some reason.

export default function Parent() {
  const [post, setPost] = useState([]);

  useEffect(() => {
    const fetchPost = async () => {
      await axios.get("http://localhost:xxxxx").then((res) => {
        setPost(res.data);
      });
    };
    fetchPost();
  }, []);

  return post ? <Child post={post} /> : null;
}

Or defensively render null in Child if post prop is undefined/falsey.

export default function Child({ post }) {
  return post ? (
    <>
      .... child post JSX
    </>
  ) : null;
}

Or provide an initial value if post is undefined. Note that this misses the edge case if post prop exists and is some other falsey value (null, 0, false, etc), so beware.

export default function Child({ post = [] }) {
  return (
    <>
      .... child post JSX
    </>
  );
}

Upvotes: 1

Related Questions