Today's question
Create a React application that allows users to create, display and delete blog posts.
Solution
The first step is to evaluate the boilerplate provided. There are 3 boilerplate files:
Home.js
import React from "react";
import Input from "./Input";
import PostDisplay from "./PostDisplay";
function Home() {
return (
<div className="text-center ma-20">
<div className="mb-20">
<Input />
<button data-testid="create-button" className="mt-10">
Create Post
</button>
</div>
<div className="posts-section">
<PostDisplay />
</div>
</div>
);
}
export default Home;
Input.js
import React, { useState } from "react";
function Input() {
return (
<div className="layout-column justify-content-center align-items-center">
<input className="w-100" type="text"
placeholder="Enter Title" value={"Title"} data-testid="title-input" />
<textarea className="mt-10 w-100"
placeholder="Enter Description" value={"Description"} data-testid="description-input" />
</div>
);
}
export default Input;
PostDisplay.js
import React from "react";
function PostDisplay() {
return (
<div data-testid="posts-container" className="flex wrap gap-10">
<div className="post-box">
<h3>{"Title"}</h3>
<p>{"Description"}</p>
<button>Delete</button>
</div>
</div>
);
}
export default PostDisplay;
The Home component(file) is provided as the parent component, which manages the state of the application. So, variable states for all blog posts, and a single new blog post will be created. The input component is responsible for creating new blog posts, therefore, the variable states for new blogs will be passed into it after it has been created in the Home component. Then, the PostDisplay component, which handles showing all blog posts, will have the state for all blog posts passed into it.
Creating the states and passing them into their respective components will look like this:
const [posts, setPosts] = useState([]);
const [newPost, setNewPost] = useState("");
...
<Input newPost={newPost} setNewPost={setNewPost} />
...
<PostDisplay posts={posts} />
The functions to create and delete posts also have to be created in the Home component and then passed into the Input and PostDisplay components, respectively. The final Home component will look like this:
import React, { useState } from "react";
import Input from "./Input";
import PostDisplay from "./PostDisplay";
function Home() {
const [posts, setPosts] = useState([]);
const [newPost, setNewPost] = useState({ title: "", description: "" });
const handleCreatePost = () => {
if (newPost.title.trim() && newPost.description.trim()) {
setPosts([...posts, { ...newPost, id: Date.now() }]);
setNewPost({ title: "", description: "" });
}
};
const handleDeletePost = (id) => {
setPosts(posts.filter(post => post.id !== id));
};
return (
<div className="text-center ma-20">
<div className="mb-20">
<Input
newPost={newPost}
setNewPost={setNewPost}
/>
<button
data-testid="create-button"
className="mt-10"
onClick={handleCreatePost}
>
Create Post
</button>
</div>
<div className="posts-section">
<PostDisplay
posts={posts}
onDelete={handleDeletePost}
/>
</div>
</div>
);
}
export default Home;
The function to create posts (handleCreatePost) firstly checks that both the title and the description fields are not empty. When that condition is true, the new post is then added to the array that will be displayed, and the title and description fields are erased. The function to delete a post takes the id of the post selected, and then removes everything about the post using the id.
The Input component will take in the newPost and setNewPost variable passed into it from the Home component. Then, the functions to handle changes in the title and description fields are created
import React from "react";
function Input({ newPost, setNewPost }) {
const handleTitleChange = (e) => {
setNewPost({ ...newPost, title: e.target.value });
};
const handleDescriptionChange = (e) => {
setNewPost({ ...newPost, description: e.target.value });
};
return (
<div className="layout-column justify-content-center align-items-center">
<input
className="w-100"
type="text"
onChange={handleTitleChange}
placeholder="Enter Title"
value={newPost.title}
data-testid="title-input"
/>
<textarea
className="mt-10 w-100"
onChange={handleDescriptionChange}
placeholder="Enter Description"
value={newPost.description}
data-testid="description-input"
/>
</div>
);
}
export default Input;
The PostDisplay component will take in the posts variable and the function to delete posts. The posts array will be mapped to the div to display the posts on the UI, and the delete function will be added to the delete button
import React from "react";
function PostDisplay({ posts, onDelete }) {
return (
<div data-testid="posts-container" className="flex wrap gap-10">
{posts.map(post => (
<div key={post.id} className="post-box">
<h3>{post.title}</h3>
<p>{post.description}</p>
<button
onClick={() => onDelete(post.id)}
data-testid={`delete-button-${post.id}`}
>
Delete
</button>
</div>
))}
</div>
);
}
export default PostDisplay;
That's all folks!
Top comments (0)