x19
x19

Reputation: 8783

React and MobX: typeError: Cannot read property 'Description' of undefined

I have used React 17, MobX and Typescript in my project.

In postDetails.tsx file, I want to show the article but I got this error:

TypeError: Cannot read property 'Description' of undefined.

While the data is available, the status cannot be updated!

(I just found out that I did not receive the updated status. It means that I receive the last value of the state.)

How can I solve the problem?

The error

If I comment this line of code, {/* <h1>{(postStore.postDetails.Description)}</h1> */}, you can see the order of the execution line code. It's not correspondig to the order of line code! content of return() has no any fetched data

import React, { useEffect } from "react";
import { useParams } from "react-router-dom";
import { observer } from "mobx-react-lite";
import { useStore } from "../../app/stores/store";
import "./postDetails.css";
import { runInAction, toJS } from "mobx";

export default observer(function PostDetails() {
    const { postStore } = useStore();
    let { id } = useParams<{ id?: string }>();

    console.log("0001 - before useEffect");

    useEffect(() => {
        console.log("0002 - in useEffect");
        try {
            runInAction(async () => {
                await postStore.details(id);
            })
            console.log("0003 - after executing postStore.details(id)");
            console.log("postStore.selectedPost : ", toJS(postStore.selectedPost));
        }
        catch (error) { }

    }, [id, postStore]);

    console.log("0004 - right after the useEffect");


    console.log("just befor return: ", postStore.postDetails);
    return (
        <>
            {console.log("0005 - I expected first run useEffect for getting the data.")}
            /* The data is not available */
            {<h1>{(postStore.postDetails.Description)}</h1>} 
        </>
    )
})

postStore.ts:

selectedPost: IPostModel | undefined = undefined;

 details = async (id: string) => {
        this.loadingInitial = true;
        try {
            const detailPost = await agent.Post.details(id);
            runInAction(() => {
                this.selectedPost = detailPost;
            })
        }
        catch (error) {
            console.log(error);
            this.setLoadingInitial(false);
        }
    }

Upvotes: 0

Views: 756

Answers (1)

Danila
Danila

Reputation: 18516

In addition to my comment: your code should be something like that:

export default observer(function PostDetails() {
  const { postStore } = useStore();
  let { id } = useParams<{ id?: string }>();

  useEffect(() => {
    postStore.details(id)
  }, [id, postStore]);


  if (!postStore.postDetails) {
    return <div>Loading...</div>
  }

  return (
    <h1>{(postStore.postDetails.Description)}</h1>
  )
})

Just handle the case when details is not yet available.

Or you can add isLoading flag to your store to make it more transparent what is going on.

Upvotes: 1

Related Questions