CuriosCoder
CuriosCoder

Reputation: 121

How to fetch nested data in react

Question regarding fetching nested data in react.

APIs

  1. https://jsonplaceholder.typicode.com/posts
  2. https://jsonplaceholder.typicode.com/posts/${postId}/comments

Able to fetch list of posts. now want to fetch list of comments from when click on post

here is code so far

import React, { useEffect, useState } from "react";
import Post from "./Post";

const [posts, setPosts] = useState([]);
const [comments, setComments] = useState([]);

function App() {
  const [posts, setPosts] = useState([]);
  const [comments, setComments] = useState([]);

useEffect(() => {
  const loadposts = async() => {
    const resp = await fetch("https://jsonplaceholder.typicode.com/posts?userId=1");
    const data = await resp.json();
    setPosts(data);
  }
  loadposts();
}, []);

return (
  <div className="App">
    <ul>
      {posts.map((post) => 
      (
        <div>
          <li key={post.id}>
            <Post 
            userId={post.id}
            title={post.title} 
            body={post.body} 
            />
          </li>
      </div>
      ))
      }
    </ul>
  </div>
);
}

export default App;

function Post({title, body, postId}) {
  
  return (
      <div>
          <h5>{postId}</h5>
          <h1>{title}</h1>
          <p>{body}</p>
      </div>
  )
}

export default Post

appreciate any help. thanks

Upvotes: 0

Views: 1501

Answers (2)

CuriosCoder
CuriosCoder

Reputation: 121

Working solution if anyone looking for


function Post() {
const {id} = useParams();
const [comments, setComments] = useState([]);

useEffect(() => {
    fetch(`https://jsonplaceholder.typicode.com/posts/${id}/comments`)
    .then((res) => res.json())
    .then(setComments)
    .catch((error) => {
        console.log(error)
    })
    console.log("setComments: ", setComments)
}, [])

    return (
        <div>
            {comments && comments.map((comment) => (
                <div key={comment.id}>
                    <p>{comment.body}</p>
                </div>

            ))}

        </div>
    )
}
export default Post

then update rendering 

    <div className="App">
      <Switch>
     <Route exact path='/'>
        {posts.map((post) => (
         <article key={post.id}> 
          <h1>{post.title}</h1>
            <Link to ={`/${post.id}`}>
              <p>{post.body}</p>
            </Link>
       </article>
      ))}
   </Route>

     <Route path ='/:id'>
        <Post/>
     </Route>
   </Switch>

  </div>

   

    
  

Upvotes: 0

Drew Reese
Drew Reese

Reputation: 202721

Firstly, the "/posts" endpoint returns posts by users, so the query "/posts?userId=1" will return all the posts by user id 1. You mistakenly passed a userId prop to the Post component instead of the specific post's id, i.e.

<Post userId={post.id} title={post.title}  body={post.body} />

The React key should also be placed on the outer-most element being mapped, the div in your case, but since li is already a block level element the div is basically extraneous.

<ul>
  {posts.map((post) => (
    <li key={post.id}> // <-- remove div and place React key on li
      <Post
        postId={post.id} // <-- pass the post's id
        title={post.title}
        body={post.body}
      />
    </li>
  ))}
</ul>

In Post component create a fetch comments utility and click handler, and attach the click handler to the title header. Conditionally render the comments. If it wasn't already clear, you'll move the comments state into Posts so each post component maintains its own copy. The following is an example for rendering out the comments once fetched, you can use whatever conditional rendering and field subset of your choosing.

const fetchComments = async (postId) => {
  const response = await fetch(
    `https://jsonplaceholder.typicode.com/posts/${postId}/comments`
  );
  return response.json();
};

function Post({ title, body, postId }) {
  const [comments, setComments] = useState([]);

  const clickHandler = () => {
    fetchComments(postId).then(setComments);
  };

  return (
    <div>
      <h5>{postId}</h5>
      <h1 onClick={clickHandler}>{title}</h1>
      <p>{body}</p>
      {comments.length && (
        <>
          Comments:
          <ul>
            {comments.map(({ id, email, name, body }) => (
              <li key={id}>
                <dl>
                  <dt>{email} - {name}</dt>
                  <dd>{body}</dd>
                </dl>
              </li>
            ))}
          </ul>
        </>
      )}
    </div>
  );
}

Edit how-to-fetch-nested-data-in-react

Upvotes: 2

Related Questions