DEV Community

loading...
Cover image for Build a Blog App with React - Components and Hooks (Part 3)

Build a Blog App with React - Components and Hooks (Part 3)

Kumar Shubham
Full Stack Web Development | Studies at IIT BHU
Originally published at shubhamstudent5.Medium ・3 min read

Hello everyone! So, this is going to be the third part of the React blog app series. In the first part, we discussed how we could start a new React project, and we learnt how to set up a Git repository to track our changes. Also, we had a look at the package.json file.

Notice: I will publish the complete detailed version of all the articles on the Medium website. Here I will give an overview and give the codes for the various pages part by part.
So, please click here to go to Medium and read it in completion. (These are friend links so do not worry about paywall)

Then, in the second part, we started to build our components. First, we got an overview of all our components and how they should work. Next, we built out the Home and the BlogList component.

In the third part, I will be dealing with the other important components like the Blog detail component, the Create new blog component and the useFetch custom hook in this part.

I would then include all other components and the local server part in the fourth part of the series.

BlogDetails Component

This is the component where we fetch and display a single blog post. So, as you remember, we call this component using a Link passing in the web address. So, we included a blog’s id in the URL as a param.

So, we will extract the id using the getParams() hook. We then use our useFetch custom hook to get that particular blog by passing in the id in the useFetch hook.

import { useParams, useHistory } 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>}
            <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;
Enter fullscreen mode Exit fullscreen mode

Create Component

This is the component we use to create new blogs in our React app. It makes use of two hooks useState and useHistory.

import { useState } from 'react';
import { useHistory } from 'react-router-dom';

const Create = () => {
    const [title, setTitle] = useState('');
    const [body, setBody] = useState('');
    const [author, setAuthor] = useState('Shubham');
    const [isPending, setIsPending] = useState(false);
    const history = useHistory();

    const handleSubmit = (e) => {
        e.preventDefault();
        const blog = { title, body, author };

        setIsPending(true);

        fetch('http://localhost:8000/blogs', {
            method: 'POST',
            headers: {"Content-Type": "application/json"},
            body: JSON.stringify(blog)
        }).then(() => {
            setIsPending(false);
            history.push('/');
        })
    }

    return ( 
        <div className="create">
            <h2>Add a New Blog</h2>
            <form onSubmit={handleSubmit}>
                <label>Blog Title</label>
                <input 
                    type="text"
                    required
                    value={title}
                    onChange={(e) => setTitle(e.target.value)}
                />
                <label>Blog Body:</label>
                <textarea
                    required
                    value={body}
                    onChange={(e) => setBody(e.target.value)}
                />
                <label>Blog author:</label>
                <select
                    value={author}
                    onChange={(e) => setAuthor(e.target.value)}
                >
                    <option value="Shubham">Shubham</option>
                    <option value="Satyam">Satyam</option>
                    <option value="Anmol">Anmol</option>
                </select>
                {!isPending && <button>Add Blog</button>}
                {isPending && <button disabled>Adding Blog</button>}
            </form>
        </div>
     );
}

export default Create;
Enter fullscreen mode Exit fullscreen mode

useFetch hook

In this component, we build the useFetch custom hook, which helps us fetch the data from our local JSON server.

import { useState, useEffect } from 'react';

const useFetch = (url) => {
    const [data, setData] = useState([]);
    const [isPending, setIsPending] = useState(true);
    const [error, setError] = useState(null);

    useEffect(() => {
        const abortCont = new AbortController();

        setTimeout(() => {
            fetch(url, { signal: abortCont.signal })
            .then(res => {
                if(!res.ok)
                {
                    throw Error('Could not fetch data for that resource');
                }
                return res.json();
            })
            .then((data) => {
                setData(data);
                setIsPending(false);
                setError(null);
            })
            .catch((err) => {
                if(err.name==='AbortError') {
                    console.log('Fetch aborted');
                }
                else {
                    setError(err.message);
                    setIsPending(false);
                }
            })
        }, 5);

        return () => abortCont.abort();
    },[url]);

    return {data, isPending, error};
}

export default useFetch;
Enter fullscreen mode Exit fullscreen mode

So, this was it for this part. In the next part of the series, we will finish up the blog app by dealing with all the leftover components, which are small, and we will also learn how to set up our local JSON server from where we are fetching all the data.

I hope you all loved the article, and I hope you are excited for the next part of the series, which will wrap up the blog project.

To read the complete tutorial, please move to Medium and read the complete article.

Discussion (0)