Hi I'm writing code to get JSON with axios in custom hooks and return the value, but I can't access the object property even it was there.
I have been trying to access like item.title
or item["title"]
and even JSON.parse()
but parse()
returned cross origin error.
customHooks.js
import { useState, useEffect } from "react";
import axios from "axios";
const GetPost = (id) => {
const [post, setPost] = useState();
useEffect(() => {
axios.get(`http://localhost:8000/post/${id}`).then((res) => setPost(res));
}, []);
return post;
};
export default GetPost;
Function where hook is called and I want to access the object:
import React from "react";
import getPost from "../customHooks/GetPost";
import { Jumbotron, Container } from "react-bootstrap";
const PostDetail = (props) => {
const item = getPost(props.match.params.id);
console.log(item); // i can access the object
console.log(item.title); //TypeError: Cannot read property 'title' of undefined
return (
<Jumbotron fluid>
<Container>
{/* <h1>{item.title}</h1>
<p>{item.description}</p> */}
</Container>
</Jumbotron>
);
};
export default PostDetail;
The actual response from server http://localhost:8000/post/post_5e9cbf07b44c7 is:
{
"message": "success",
"item": {
"post_id": "post_5e9cbf07b44c7",
"title": "Asperiores.",
"description": "Porro iure aliquam laborum veniam quis vel. At itaque voluptas voluptas natus eligendi aut facilis.",
"content": "lorem ipsum",
"img_url": "https://lorempixel.com/100/100/cats/?61693",
"created_by": "user_5e9cbf07b48fc",
"created_at": "2020-04-19 21:13:43",
"updated_at": "2020-04-19 21:13:43"
}
}
The value of console.log(item)
in PostDetail.js is:
{
"data": {
"message": "success",
"item": {
"post_id": "post_5e9cbf07b44c7",
"title": "Asperiores.",
"description": "Porro iure aliquam laborum veniam quis vel. At itaque voluptas voluptas natus eligendi aut facilis.",
"content": "lorem ipsum.",
"img_url": "https://lorempixel.com/100/100/cats/?61693",
"created_by": "user_5e9cbf07b48fc",
"created_at": "2020-04-19 21:13:43",
"updated_at": "2020-04-19 21:13:43"
}
},
"status": 200,
"statusText": "OK",
"headers": {
"cache-control": "no-cache, private",
"content-type": "application/json"
},
"config": {
"url": "http://localhost:8000/post/post_5e9cbf07b44c7",
"method": "get",
"headers": {
"Accept": "application/json, text/plain, */*"
},
"transformRequest": [
null
],
"transformResponse": [
null
],
"timeout": 0,
"xsrfCookieName": "XSRF-TOKEN",
"xsrfHeaderName": "X-XSRF-TOKEN",
"maxContentLength": -1
},
"request": {}
}
thanks in advance :)
The problem happens when you try to access the returned value because on initial render the value is not available since the effect runs post render cycle and also because the axios request is async.
It will however work if you actually initialize the state to object within your custom hook
Also make sure that you set res.data.item
in the state and not res
. Post that you can get the value with item.title
SideNotes:
Please ensure that you prefix your custom hooks names with use
which actually helps eslint figure out the distinction between custom hook or a function.
Also since you are making an API call based on param id, I advice you to pass that id as a dependency to useEffect in custom hook so that the scenarios where id is changed also work seamlessly
import { useState, useEffect } from "react";
import axios from "axios";
const useGetPost = (id) => {
const [post, setPost] = useState({}); // initialize here
useEffect(() => {
axios.get(`http://localhost:8000/post/${id}`).then((res) => setPost(res.data.item));
}, [id]); // pass id as a dependency here
return post;
};
export default useGetPost;
Use it in PostDetail component like
import React from "react";
import useGetPost from "../customHooks/GetPost";
import { Jumbotron, Container } from "react-bootstrap";
const PostDetail = (props) => {
const item = useGetPost(props.match.params.id);
console.log(item);
console.log(item.title);
return (
<Jumbotron fluid>
<Container>
{/* <h1>{item.title}</h1>
<p>{item.description}</p> */}
</Container>
</Jumbotron>
);
};
export default PostDetail;