Getting Started with React: Creating Your Own Blog App - Part 5

Elevate Your React Blog App: Formik, Yup, and Search Features

Getting Started with React: Creating Your Own Blog App - Part 5

Introduction

In this article of our React blog series, we will implement a search feature and a profile page for our blog. This will allow your name to be automatically updated based on the information you provide in your profile. Additionally, we will be using a form library to handle and manage our forms effectively.

This blog post will enhance your understanding of React and make learning it a more straightforward process.

A quick note before we begin: We are building a blog app, and this blog series focuses on learning React through hands-on projects. This will be a basic app without any high-level concepts in React, but in the future, I will introduce some advanced concepts to enhance your understanding.

If you are new to React, I suggest you read my previous blog posts where I explain and demonstrate how to install React with Vite, along with other project setup steps and CRUD operations. I highly encourage you to read those blog posts before continuing with this one.

Prerequisites

What will we be learning in this blog post?

In our previous blog, we learned basic CRUD operations without using any form library. We implemented basic validation, but things can get more complicated if you have multiple text fields in the form. Managing each text field individually can be a pain.

In this blog post, we will learn how to handle forms using form libraries such as Formik and Yup. These libraries can manage forms in an easy and efficient manner. You won't need to write any regex or validation for your text fields. These libraries will take care of everything with just a few lines of code. We will also implement basic form validation.

Additionally, we will implement a search feature for our blog. A search feature is crucial in every app. Our goal is to find and display blogs based on search queries. Although we will primarily use plain JavaScript, we will also learn how to implement this functionality in React.

I intentionally added a few bugs in this code. I encourage you to find those bugs, raise an issue in my GitHub repo, and create a Pull Request to resolve them.

When you search for and fix issues in React, you learn by doing, become better at solving puzzles, and gain a stronger grasp of how things work. This makes you more capable and confident in React.

Creating a Profile Page

In this profile page, we will add two text fields: Name and Designation. This will simplify the process and make it easier to understand how to implement Formik and Yup in React.

Installing Formik and Yup Packages

Open up your VSCode terminal and navigate to your project directory, and use npm to install the formik, yup package:

npm install formik yup

Yup and Formik are popular libraries in the React ecosystem, used for form handling and validation. They offer tools to make form management more streamlined and user-friendly.

Here's an overview of each:

  1. Yup:

    • Yup is a JavaScript library that focuses on form schema validation. It allows you to define a schema for your form data and then validate that data against the schema.

    • With Yup, you can define rules for each field, such as required fields, minimum and maximum lengths, and custom validation functions.

    • It's commonly used in conjunction with form libraries like Formik to provide validation for form inputs.

  2. Formik:

    • Formik is a complete solution for building forms in React. It simplifies the process of managing form state, validation, submission, and error handling.

    • Formik handles form state and validation, including field values, touched state, and error messages.

    • It provides a way to define form submission logic and handles the asynchronous nature of form submissions.

    • Formik also integrates smoothly with other libraries like Yup for validation.

These packages save your development time and give more flexibility in handling your forms.

profile.jsx

import { Button, Container, Form } from "react-bootstrap";
import * as formik from 'formik';
import * as yup from 'yup';


//Local imports
import CustomInputText from "../components/customInputText";
import { getDesignationLocalStore, getNameLocalStore, saveDesignationLocalStore, saveNameLocalStore } from "../utils/local_storage";

function Profile() {

    const { Formik } = formik;
    const schema = yup.object().shape({
      name: yup.string.required(),
      designation: yup.string().required(),
    });

    const onSubmitProfile = (formValues) => {
      saveNameLocalStore(formValues.name);
      saveDesignationLocalStore(formValues.designation);
    }


  return (
        <div className="main-content">
      <Container>
        <h2 className="mb-4">Your Profile</h2>
    <Formik
      validationSchema={schema}
      onSubmit={(values) => onSubmitProfile(values)}
      initialValues={{
        name: getNameLocalStore() ? getNameLocalStore() : '',
        designation: getDesignationLocalStore() ? getDesignationLocalStore() : '',
      }}
    >
      {({ handleSubmit, handleChange, values, touched, errors }) => (
        <Form noValidate onSubmit={handleSubmit}>

             <CustomInputText 
          inputLabel={"Name"}
            inputPlaceholder={"Enter your Name"}
            inputType={"text"}
            inputValidationMsg={"Please add your Name"}
            inputValue={values.name}
            inputOnChange={handleChange}
            inputIsValid={touched.name && errors.name}
            inputFieldname={'name'}
            />
            <CustomInputText 
          inputLabel={"Designation"}
            inputPlaceholder={"Enter your designation"}
            inputType={"text"}
            inputValidationMsg={"Please add your designation"}
            inputValue={values.designation}
            inputOnChange={handleChange}
            inputIsValid={touched.designation && errors.designation}
            inputFieldname={'designation'}
            />
          <Button type="submit" className="btn btn-primary btn-custom w-100">Save Profile</Button>

        </Form>
      )}
    </Formik>
    </Container>
    </div>
  );

}

export default Profile;

Let's break down the code step by step:

  1. Import Statements:

    • The component imports required components and libraries from react-bootstrap for styling, and it imports formik and yup for handling forms and form validation.
  2. Profile Component:

    • This is a functional component named Profile.
  3. schema Definition:

    • A schema for form validation is defined using the yup library. It specifies that both name and designation are required fields.
  4. onSubmitProfile Function:

    • This function is called when the form is submitted. It uses the local storage utility functions to save the user's name and designation.
  5. Return Statement:

    • The component's JSX structure is returned within a Container element.

    • It includes a heading "Your Profile".

    • The Formik component wraps the form, providing form handling and validation.

    • Within the Formik component, there's a callback function that receives handleSubmit, handleChange, values, touched, and errors as parameters. These are provided by Formik for form handling and validation.

    • Two instances of the CustomInputText component are used to handle the name and designation inputs. The props passed include the label, placeholder, type, validation message, input value, input change handler, and validation status based on touched and errors.

    • A "Save Profile" button is included that triggers form submission.

  6. Formik Initialization:

    • The Formik component is initialized with the specified validation schema, onSubmit function, and initial values for name and designation. The initial values are retrieved from local storage if available.
  7. CustomInputText Component:

    • The CustomInputText component is used to render the input fields with consistent styling.

    • The props passed to this component include information for rendering and handling the input field.

The form uses Formik for form management and Yup for form validation. The form data is saved to local storage upon submission. The CustomInputText component is used to render input fields consistently.

Implementing the Search Feature

import { Stack, Container, Row, Col, Form } from "react-bootstrap";
import PropTypes from "prop-types";
import { useNavigate } from "react-router-dom";


// Local Imports
import BlogItem from "../components/blogItem";
import "../css/homepage.css";
import { useState } from "react";
import { getNameLocalStore } from "../utils/local_storage";


function Homepage({ blogListData }) {

  const [search, setSearch] = useState('');
  const navigate = useNavigate();

  console.log(blogListData);

  const onBlogItemClick = (blogId) => {
    navigate({pathname:'/blog', search:`?blogID=${blogId}`});
    console.log("Blog Click");
  }


  return (
    <div className="main-content">
      <Container>
        <section id="search-section">
          <Row>
            <Col>
              <div className="searchfield">
                <Form.Control type="text" placeholder="Search Blog" onChange={(e) => setSearch(e.target.value)}/>
                <i className="fa fa-search" aria-hidden="true"></i>
              </div>
            </Col>
          </Row>
        </section>
        <section id="bloglist-title-section">
          <div className="bloglist-title">
            <h2>All Blogs</h2>
            <i className="fa fa-file-text-o" aria-hidden="true"></i>
          </div>
        </section>
        <section id="bloglist-section">
          <Stack gap={3}>
            {blogListData.length === 0 ? (
              <p style={{ textAlign: "center" }}>No Blogs are available ๐Ÿ˜”</p>
            ) : (

              blogListData.filter((blogItem) => blogItem.title.toLowerCase().includes(search.toLowerCase())).map((filteredBlogItem, index) => {return <BlogItem
                  key={index}
                  blogTitle={filteredBlogItem.title}
                  blogAuthor={getNameLocalStore() ? getNameLocalStore() : "Anonymous"}
                  blogTimeAndDate={filteredBlogItem.date}
                  blogAuthorImage={
                    "https://api.dicebear.com/6.x/open-peeps/svg?face=angryWithFang,calm,blank"
                  }
                  onBlogClick={() => onBlogItemClick(index)}
                />})
            )}
          </Stack>
        </section>
      </Container>
    </div>
  );
}

Homepage.propTypes = {
  blogListData: PropTypes.any,
};

export default Homepage;

In this code, we have implemented a search feature to filter and display blog items based on the search input.

Here's how it works:

  1. Add State for Search: You've used the useState hook to manage the search state, which represents the user's search input.

  2. Search Input: In the Form.Control component, you've added an onChange event handler that updates the search state based on the user's input.

  3. Filtering and Mapping Blog Items: Inside the blogListData array, you're using the filter method to filter out blog items whose titles include the search input (case-insensitive). Then, you're using the map method to render the filtered blog items using the BlogItem component.

  4. Displaying Search Results: The filtered blog items are displayed based on the search input. If the search input matches the title of any blog item, it will be displayed in the list.

  5. onBlogItemClick Function: When a blog item is clicked, the onBlogItemClick function is called, and you're using the useNavigate hook to navigate to the "/blog" route with the appropriate blogID query parameter.

Overall, this code allows users to search for specific blog items by title and displays the matching results dynamically as the user types in the search input.

You can get all this code from github repository

Run your APP

Simply run the following command in your terminal:

npm run dev

Now give yourself a pat on the back, as you've just implemented a profile page using Formik and Yup, the search feature in our React app.

So, that concludes this blog post.

What's Next?

Now you have grasped the basics of React and some useful packages that can be used in any React app. In the next blog post, we will demonstrate how to display blog content that we have added and showcase it using dynamic routes.

Conclusion

In conclusion, this article covered how to create a profile page using Formik and Yup in a React blog app, as well as implementing a search feature.

By following this tutorial, you have gained a better understanding of form handling, validation, and managing state in React applications.

Follow me on Twitter or Linkedin I share about Cloud, System Design, Code, and many more tech stuff ๐Ÿ˜Š

Resources

Did you find this article valuable?

Support Pradhuman Blog by becoming a sponsor. Any amount is appreciated!

ย