iamshaunjp / Complete-React-Tutorial

All course files for the Complete React Tutorial on the Net Ninja YouTube channel.
1.81k stars 1.72k forks source link

Proper way to update state in Home when deleting a blog record in BlogList component? #10

Open mrdc opened 2 years ago

mrdc commented 2 years ago

Hi Shaun,

THANKS for incredible videos!

I have a small question concerning state update, when we delete a blog record directly from Home in BlogList component, not in BlogDetails.

In Lesson 13 we've used the callback function to handle delete:

import { useState } from "react";
import BlogList from "./BlogList";

const Home = () => {
  const [blogs, setBlogs] = useState([
    { title: 'My new website', body: 'lorem ipsum...', author: 'mario', id: 1 },
    { title: 'Welcome party!', body: 'lorem ipsum...', author: 'yoshi', id: 2 },
    { title: 'Web dev top tips', body: 'lorem ipsum...', author: 'mario', id: 3 }
  ])

  const handleDelete = (id) => {
    const newBlogs = blogs.filter(blog => blog.id !== id);
    setBlogs(newBlogs);
  }

  return (
    <div className="home">
      <BlogList blogs={blogs} title="All Blogs" handleDelete={handleDelete} />
    </div>
  );
}

export default Home;
const BlogList = ({ blogs, title, handleDelete }) => {
  return (
    <div className="blog-list">
      <h2>{ title }</h2>
      {blogs.map(blog => (
        <div className="blog-preview" key={blog.id} >
          <h2>{ blog.title }</h2>
          <p>Written by { blog.author }</p>
          <button onClick={() => handleDelete(blog.id)}>delete blog</button>
        </div>
      ))}
    </div>
  );
}

export default BlogList;

Then in Lesson 31 we've moved all logic to useFetch hook, so state is updated for BlogDetails page:

import { useHistory, useParams } from "react-router-dom";
import useFetch from "./useFetch";

const BlogDetails = () => {
  const { id } = useParams();
  const { data: blog, error, isPending } = useFetch('http://localhost:8000/blogs/' + id);
  const history = useHistory();

  const handleClick = () => {
    fetch('http://localhost:8000/blogs/' + blog.id, {
      method: 'DELETE'
    }).then(() => {
      history.push('/');
    }) 
  }

  return (
    <div className="blog-details">
      { isPending && <div>Loading...</div> }
      { error && <div>{ error }</div> }
      { blog && (
        <article>
          <h2>{ blog.title }</h2>
          <p>Written by { blog.author }</p>
          <div>{ blog.body }</div>
          <button onClick={handleClick}>delete</button>
        </article>
      )}
    </div>
  );
}

export default BlogDetails;

And what if I want to add delete button directly to the BlogList component to delete a blog record from Home page? What is the easiest or the best approach to achieve something like this?

Notice handleDeleteClick is in BlogList not in BlogDetails.

import { Link } from "react-router-dom";

const BlogList = ({blogs, title}) => {
    const handleDeleteClick = (id) => {
        fetch(`http://localhost:8000/blogs/${id}`, {
            method: 'DELETE'
        });
    }

    return (
        <div className="blog-list"> 
        <h2>{title}</h2>
        {blogs.map((blog) => (
            <div className="blog-preview" key={blog.id}>
                <Link to={`/blogs/${blog.id}`}> 
                    <h2>{blog.title}</h2>
                    <p>Written by {blog.author}</p> 
                    <button onClick={ () => handleDeleteClick(blog.id) }>delete</button>
                </Link>
            </div>
        ))}   
        </div>
    );
}

export default BlogList;
import './BlogList'
import BlogList from "./BlogList";
import useFetch from "./hooks/useFetch";

const Home = () => {
   const {data: blogs, isPending, error} = useFetch('http://localhost:8000/blogs');

   return ( 
      <div className="home">
         { error && <div className="fetchError"> {error} </div>}
         {isPending && <div className="loading">loading...</div>}
         {blogs && <BlogList blogs={blogs} title="All Blogs"  />}
      </div>
   );
}

export default Home;

Thanks!