Build a Blog App with React - Components and Hooks (Part 3)
Kumar Shubham
Posted on June 19, 2021
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;
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;
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;
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.
Posted on June 19, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.