0

I have an API that responds with the following object:-

[
  {
     "A":4,
     "B":3,
     "C":2,
     "D":1,
  }
]

I want to display the object data in the following component:-

export default function name() {
  const dispatch = useDispatch();

  const { postsInfo } = useSelector((state) => state.posts);

  useEffect(() => {
    dispatch(getPostsInfo());
  }, [dispatch]);

  console.log(postsInfo[0]);

  return (
    <>
      <div className="db-wrapper">
        <div className="cards-container">
          <Card title={"A"} value={postsInfo[0].A} />
          <Card title={"B"} value={postsInfo[0].B} />
          <Card title={"C"} value={postsInfo[0].C} />
          <Card title={"D"} value={postsInfo[0].D} />
        </div>
      </div>
    </>
  );
}

but whenever the page is rendered it throws an error in the console log and nothing is shown on the page.

Uncaught TypeError: Cannot read properties of undefined (reading '0')
3
  • What's the initial state look like? I'm guessing it has posts as undefined. You'll either need to check for undefined and render something different, or change the initial state so posts is an object with a [0] property Commented Apr 8, 2022 at 4:11
  • @NicholasTower yes initial state is undefined. Commented Apr 8, 2022 at 4:13
  • If postsInfo = null in initial, check postsInfo null or not. If postsInfo = [] in initial, check postsInfo.length > 0 Commented Apr 8, 2022 at 4:23

2 Answers 2

1

This is happening because it's an asynchronous process and is being mounted before useEffect ends fetching the data and populates its state.

To deal with it you can use Optional Chaining: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining

Array item access with optional chaining:

let arrayItem = arr?.[42];

Your component return will be like this:

return (
    <>
      <div className="db-wrapper">
        <div className="cards-container">
          <Card title={"A"} value={postsInfo?.[0].A} />
          <Card title={"B"} value={postsInfo?.[0].B} />
          <Card title={"C"} value={postsInfo?.[0].C} />
          <Card title={"D"} value={postsInfo?.[0].D} />
        </div>
      </div>
    </>
  );
Sign up to request clarification or add additional context in comments.

Comments

0

Welcome to asynchronous programming!

Dispatch and useEffect are asynchronous. This means that the render function continues to execute without waiting for the effect callback to complete and the dispatch to populate your redux state. As a result postsInfo is undefined on the initial render, and is only later populated on subsequent renders when the redux state changes.

Whenever you are initializing state in a react component via an asynchronous operation, your render function needs to correctly handle the state being uninitialized. The 'standard' way to do this is to return null if the state is uninitialized, like so:

if (!postsInfo) return null;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.