DEV Community

Bukunmi Odugbesan
Bukunmi Odugbesan

Posted on

Coding Challenge Practice - Question 5

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;
Enter fullscreen mode Exit fullscreen mode

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;

Enter fullscreen mode Exit fullscreen mode

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;

Enter fullscreen mode Exit fullscreen mode

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} />
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

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;
Enter fullscreen mode Exit fullscreen mode

That's all folks!

Top comments (0)