<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Babatunde Adeniran</title>
    <description>The latest articles on DEV Community by Babatunde Adeniran (@tuneshman).</description>
    <link>https://dev.to/tuneshman</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F391744%2Fce5caad4-0d55-4af6-b33c-fd9d8f8e6411.jpg</url>
      <title>DEV Community: Babatunde Adeniran</title>
      <link>https://dev.to/tuneshman</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tuneshman"/>
    <language>en</language>
    <item>
      <title>What Exactly Is Serverless? A Simple Explanation for Beginners</title>
      <dc:creator>Babatunde Adeniran</dc:creator>
      <pubDate>Wed, 10 Dec 2025 14:32:30 +0000</pubDate>
      <link>https://dev.to/tuneshman/what-exactly-is-serverless-a-simple-explanation-for-beginners-2j1k</link>
      <guid>https://dev.to/tuneshman/what-exactly-is-serverless-a-simple-explanation-for-beginners-2j1k</guid>
      <description>&lt;p&gt;It is not uncommon for people to think that there are no application servers when they hear the term "serverless." A serverless application does not mean the absence of servers. Servers actually exist, but the difference is that you do not have the responsibility of managing them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkmlzzd2wkg6gbpo0dcdh.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkmlzzd2wkg6gbpo0dcdh.jpeg" alt=" " width="408" height="124"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In a serverless application, your primary concern is your code and how well it performs. How the servers process your business logic is none of your business because AWS takes care of this. AWS does the heavy lifting by handling the patching and scaling of servers under the hood. &lt;/p&gt;

&lt;p&gt;Now, let’s simplify this by explaining it in a beginner-friendly manner. &lt;/p&gt;

&lt;h4&gt;
  
  
  Serverless, what does it really mean?
&lt;/h4&gt;

&lt;p&gt;Serverless means:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Absence of server provisioning and management: In other words, you will never have to install server updates, handle an EC2 instance, or SSH into a machine.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Automatic application scaling: Your application scaling is handled by AWS regardless of the number of requests you send through. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cost effectiveness: There are no idle costs as you are only charged for what you use. You don’t get charged if your application doesn’t run. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;High availability: Multi-AZ redundancy is taken care of by AWS. &lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;Serverless is just efficient cloud computing.&lt;/em&gt; &lt;/p&gt;

&lt;h4&gt;
  
  
  Building Blocks of Serverless on AWS
&lt;/h4&gt;

&lt;p&gt;There are so many AWS services that can be combined to build serverless applications on AWS. They include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;AWS Lambda: This is the heart of serverless on AWS. With this, you can run code without the need to provision servers. You are only saddled with the responsibility of uploading code, and AWS handles running this code in response to events like changes in the database, file uploads, and API requests. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;API Gateway: This helps us create serverless REST or WebSocket API’s. With these API’s we can do many things, such as triggering lambda functions and handling user authentication. It is a weapon for building backend services.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;S3: This is for serverless storage. It is an AWS-managed service that helps with the storage of videos and images. It can also be used to host static web pages. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;AWS DynamoDB: I wrote about DynamoDB and the 'Access Patterns' Mindset in an &lt;a href="https://dev.to/tuneshman/dynamodb-the-access-patterns-mindset-l8"&gt;earlier article&lt;/a&gt;. It is a serverless and fully managed database engine that scales automatically and is capable of handling millions of reads and writes every second. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;AWS SQS and EventBridge: This helps with serverless event management and messaging. With these, we can efficiently build a complex infrastructure that communicates with each other and connects very well. These two make it possible to architect reliable and scalable workflows. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  When should you use Serverless?
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;To build APIs&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;To run scheduled tasks&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For Webhooks&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;To process files&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For script automation &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;ETL jobs. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Basically, serverless is a great fit for event-driven workload. It is also a great fit for beginners with little or no idea of servers and DevOps processes. It is important to clarify that serverless does not mean you won’t handle architecture decisions, cost tracking, logging, and monitoring. These are still operational responsibilities you have to handle. &lt;/p&gt;

&lt;h3&gt;
  
  
  Wrapping Up!
&lt;/h3&gt;

&lt;p&gt;Serverless is a big shift in how major cloud applications are built. So, it isn’t just a trend. It focuses greatly on scalability so that you don’t have to worry about capacity provisioning. Serverless focuses on speed and not configuration. It places great focus on cost reduction and business value. As a cloud beginner, it is a good starting point because it naturally teaches you event-driven design, and it allows you to deploy applications without much setup. &lt;/p&gt;

&lt;p&gt;With serverless, you build more and do less infrastructure management.  &lt;/p&gt;

</description>
      <category>serverless</category>
      <category>aws</category>
    </item>
    <item>
      <title>RDS vs DynamoDB: When do I Choose Which?</title>
      <dc:creator>Babatunde Adeniran</dc:creator>
      <pubDate>Thu, 30 Oct 2025 14:44:40 +0000</pubDate>
      <link>https://dev.to/tuneshman/rds-vs-dynamodb-when-do-i-choose-which-8cf</link>
      <guid>https://dev.to/tuneshman/rds-vs-dynamodb-when-do-i-choose-which-8cf</guid>
      <description>&lt;p&gt;Choosing a database that matches your workload and architecture is one of the major decisions you have to make when developing an application. In AWS, this decision may not be straightforward as there are many options to choose from, with each option having its core strength and what it is optimised for. Amazon RDS and Amazon DynamoDB are some of the options to choose from when building with AWS. Both database systems are fully managed by AWS. They are both scalable, easy to set up and operate.  However, they work best for different workloads. &lt;/p&gt;

&lt;p&gt;Another big difference between &lt;code&gt;RDS&lt;/code&gt; and &lt;code&gt;DynamoDB&lt;/code&gt; is that they are optimised for different thinking models. &lt;a href="https://dev.to/tuneshman/dynamodb-the-access-patterns-mindset-l8"&gt;In an earlier article&lt;/a&gt;, I discussed the DynamoDB Access Patterns’ Mindset and why it is important not to approach DynamoDB with a relational mindset. In the same vein, you shouldn’t approach Amazon RDS like you would approach a NoSQL engine like DynamoDB. While DynamoDB is schemaless, RDS relies heavily on database schemas and relationships between entities. Therefore, you shouldn’t treat it like you would treat DynamoDB because you will run into performance issues if you do. &lt;/p&gt;

&lt;h4&gt;
  
  
  How do I decide which one to use?
&lt;/h4&gt;

&lt;p&gt;In very simple terms and in practical language, DynamoDB should be used for data that is driven by access patterns. Use DynamoDB if your workload requires low-latency and predictable access patterns. Conversely, RDS should be your choice if your data is structured, relationships between data are important, and there are joins, transactions, and schemas.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;RDS is for relational data.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;DynamoDB is for access-pattern-driven data.&lt;/em&gt; &lt;/p&gt;

&lt;h4&gt;
  
  
  How are they different?
&lt;/h4&gt;

&lt;p&gt;The big difference between RDS and DynamoDB is in how data is modelled.  &lt;/p&gt;

&lt;p&gt;In relational thinking, tables and relationships are designed first, and new query patterns can be established subsequently. Relational databases work best for ERPs, Human Resource systems, traditional business applications, and financial systems. If you choose to work with RDS, you have to handle how your connections are managed.&lt;/p&gt;

&lt;p&gt;In DynamoDB’s access-pattern thinking, our database is modelled for the queries needed by our application. Therefore, performance and scalability are not issues you need to worry about. This makes DynamoDB ideal for serverless systems, retail carts, high-traffic mobile or web applications, streaming apps, and gaming apps.  &lt;/p&gt;

&lt;h4&gt;
  
  
  When should I choose RDS?
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;For complex queries&lt;/li&gt;
&lt;li&gt;For strong ACID (Atomicity, Consistency, Isolation, Durability) guarantees. &lt;/li&gt;
&lt;li&gt;When you need joins and need to establish relationships between data.&lt;/li&gt;
&lt;li&gt;SQL is ideal for reporting and analytics requirements because it syncs well with Business Intelligence tools. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Are you working on a logistics application, bank transactions, human resources or payroll system, or inventory systems? Think RDS. &lt;/p&gt;

&lt;h4&gt;
  
  
  When should I choose DynamoDB?
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;When building a low-latency application that requires fast reads and writes.&lt;/li&gt;
&lt;li&gt;Serverless architecture - &lt;code&gt;Lambda&lt;/code&gt;, &lt;code&gt;SQS&lt;/code&gt;, etc. &lt;/li&gt;
&lt;li&gt;If your application scales massively. &lt;/li&gt;
&lt;li&gt;For predictable access patterns. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Are you working on leaderboards, real-time booking applications, shopping cart sessions, or an API rate-limiting system? Think DynamoDB.&lt;/p&gt;

&lt;h4&gt;
  
  
  Can I use both?
&lt;/h4&gt;

&lt;p&gt;The short answer is yes. Some systems use both RDS and DynamoDB. These modern systems use Amazon RDS to carry out analytics and reporting and use DynamoDB for high-volume applications with real-time data. &lt;/p&gt;

&lt;p&gt;With this hybrid arrangement, we can both carry out complex reporting and implement fast and low-cost operational workloads. &lt;/p&gt;

&lt;p&gt;Therefore, in such an arrangement, RDS is for business analysis and interpretation, while DynamoDB is for write speed. &lt;/p&gt;

&lt;h3&gt;
  
  
  Wrapping Up!
&lt;/h3&gt;

&lt;p&gt;Whether you choose RDS, DynamoDB or both depends on the system you are working on, the data you have, your technical expertise and how well you understand access patterns and the relationships between data entities. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;For structured, relational data that requires flexible queries, use RDS.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;For low-latency, highly scalable applications with an established access pattern, use DynamoDB.&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;As a competent engineer, your choice of database should hinge on suitability with the workload at hand and not on what you are most comfortable with.   &lt;/p&gt;

</description>
      <category>dynamodb</category>
      <category>aws</category>
      <category>serverless</category>
      <category>rds</category>
    </item>
    <item>
      <title>DynamoDB: The 'Access Patterns' Mindset</title>
      <dc:creator>Babatunde Adeniran</dc:creator>
      <pubDate>Wed, 22 Oct 2025 17:17:57 +0000</pubDate>
      <link>https://dev.to/tuneshman/dynamodb-the-access-patterns-mindset-l8</link>
      <guid>https://dev.to/tuneshman/dynamodb-the-access-patterns-mindset-l8</guid>
      <description>&lt;p&gt;It is well known that software development is a lifelong learning process. At the start of my career, most of my early interactions involved SQL databases. I used many SQL administrative tools, such as DBeaver, SQLiteStudio, and MySQL Workbench. When I first began working with DynamoDB, I didn’t realise early enough that I needed a mindset shift, and I am sure quite a few developers fell into a similar trap. In designing my DynamoDB table structure, I treated queries and access patterns as afterthoughts and focused more on mappings and relationships between items and entities, just as I would with a relational database. Persistently applying these old SQL habits often led me to deal with inefficient scans, which was deeply frustrating.&lt;/p&gt;

&lt;p&gt;When working with DynamoDB, you need to shift your mindset, especially if you have prior experience with relational database systems. The key focus when creating a DynamoDB table should primarily be on access patterns rather than data structure. &lt;/p&gt;

&lt;p&gt;The goal of this article is to shed light on what “designing for access patterns” means. I will explain its importance and why you cannot tap into the numerous benefits of DynamoDB without this mindset shift. &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;How does DynamoDB differ from Relational Database systems?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;For starters, and for the benefit of those who do not know what DynamoDB is, it is a NoSQL database that is highly available and performant. As a user, you do not have to worry about patching and maintenance; AWS handles this. Amazon DynamoDB is a fully managed database capable of processing millions of requests per second. &lt;/p&gt;

&lt;p&gt;With Relational databases like PostgreSQL, MySQL, and MariaDB, data can be queried in many ways. SQL-based databases are heavily dependent on JOINS and indexes, and this makes it easier to avoid data duplication. DynamoDB operates differently. As mentioned ab initio, DynamoDB is for workloads that need a high level of performance and scalability. Regardless of the number of item rows (can scale to trillions), reads and writes must be processed at a fast pace, irrespective of the database size. This is achieved by avoiding unnecessary item scans (which could be costly) and quick lookup of table items with the &lt;code&gt;Primary Key&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Look at it this way, in Relational databases, you create tables, and your database must adjust itself to whatever queries you feed it to give you a result. On the flip side, in DynamoDB, your database and table won’t conform to your queries; your queries must adapt to your database based on the data models and access patterns you have defined. &lt;/p&gt;

&lt;p&gt;DynamoDB’s access pattern mindset:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“These are the queries I have: what access patterns and data models should I create?”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Relational database:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“What queries can I write with the table/tables I have?”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When working with DynamoDB, it is best practice to list our entry points or access patterns before building. Without specifying and identifying these patterns, we wouldn't be able to outline the &lt;code&gt;Primary Key&lt;/code&gt;, &lt;code&gt;Sort Key&lt;/code&gt;, &lt;code&gt;Local Secondary Index (LSI)&lt;/code&gt;, and &lt;code&gt;Global Secondary Index (GSI)&lt;/code&gt; that we need.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Primary Keys and Indexes
&lt;/h2&gt;

&lt;p&gt;The Primary Key and Indexes are at the core of DynamoDB access patterns. For example, if we were to build a simple e-commerce backend of users and orders using a relational database, we would need to set up various tables for &lt;code&gt;Users&lt;/code&gt;, &lt;code&gt;Orders&lt;/code&gt;, &lt;code&gt;Items&lt;/code&gt;, etc. With DynamoDB, we can model this efficiently in just one table thanks to the Primary Keys and Indexes.&lt;/p&gt;

&lt;h4&gt;
  
  
  Primary Key
&lt;/h4&gt;

&lt;p&gt;You must first understand how to choose a &lt;code&gt;Primary Key&lt;/code&gt; for your DynamoDB table before any further discussions on access patterns. In choosing a &lt;code&gt;Primary Key&lt;/code&gt;, there are two options to select from. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Partition Key: This has to be unique for every row/item on the database. A unique partition key guarantees data distribution. E.g. for a user table, a good choice for a partition key would be the &lt;code&gt;user_id&lt;/code&gt; (it could be a random UUID) because of its high cardinality. We can have several other attributes, such as &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;age&lt;/code&gt;, &lt;code&gt;address&lt;/code&gt;, etc.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjo0k1dq22gdex1hfhdia.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjo0k1dq22gdex1hfhdia.png" alt=" " width="800" height="564"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Partition Key + Sort Key: The combination has to be unique for every item/row on the database. For example, in a users-orders table, the &lt;code&gt;user_id&lt;/code&gt; is an ideal candidate for the partition key, and the &lt;code&gt;orders_id&lt;/code&gt; can serve as the &lt;code&gt;sort key&lt;/code&gt;. However, it is important to emphasise that when we have a composite primary key, data grouping is done on the partition key. So, a user can have numerous orders, as seen with &lt;code&gt;user_id&lt;/code&gt; &lt;em&gt;5456789094&lt;/em&gt; below. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxmp5i5h6e5lbq4wc4g8z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxmp5i5h6e5lbq4wc4g8z.png" alt=" " width="800" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, we see the second and third items have the same partition keys but different sort keys, and their combination creates a unique primary key. &lt;/p&gt;

&lt;h4&gt;
  
  
  LSI (Local Secondary Index)
&lt;/h4&gt;

&lt;p&gt;This is the first of the 2 kinds of indexes. It gives us another &lt;code&gt;sort key&lt;/code&gt; for querying our DynamoDB table while maintaining the same &lt;code&gt;partition key&lt;/code&gt;. We cannot define an &lt;code&gt;LSI&lt;/code&gt; after the table has been created, and we can have up to 5 LSIs per table. At the moment, we can only do a query on &lt;code&gt;user_id&lt;/code&gt; and &lt;code&gt;order_id&lt;/code&gt;. We haven’t devised a means to do a query on &lt;code&gt;user_id&lt;/code&gt; and &lt;code&gt;order_item&lt;/code&gt;. The LSI makes it possible to perform this query. Therefore, we can get all the items ordered by a particular user.&lt;/p&gt;

&lt;h4&gt;
  
  
  GSI (Global Secondary Index)
&lt;/h4&gt;

&lt;p&gt;What if we wanted to get the items that are in a particular order? At the moment, there is no way to do this, and that’s where &lt;code&gt;GSIs&lt;/code&gt; come in. This gives us an alternate primary key that is different from the primary key we defined in our base table definition. We can create a &lt;code&gt;GSI&lt;/code&gt; after initial table creation, and it makes it faster to query on non-key attributes. To get the item in an order, we can specify the &lt;code&gt;order_id&lt;/code&gt; as the new partition key and the item as the new sort key. The &lt;code&gt;user_id&lt;/code&gt;, &lt;code&gt;order_quantity&lt;/code&gt;, &lt;code&gt;name&lt;/code&gt;, and &lt;code&gt;address&lt;/code&gt; become the attributes. &lt;/p&gt;

&lt;h3&gt;
  
  
  Wrapping Up!
&lt;/h3&gt;

&lt;p&gt;When working with DynamoDB, data modelling is more about access patterns and query entry points than tables and how they are related. It's more about how your application reads and writes data. Adopting the access pattern mindset makes it possible to enjoy the immense benefits of DynamoDB as a serverless and scalable database. &lt;/p&gt;

</description>
      <category>dynamodb</category>
      <category>aws</category>
      <category>serverless</category>
    </item>
    <item>
      <title>Formik &amp; React (Part 3): Validation with yup &amp; Streamlining Code</title>
      <dc:creator>Babatunde Adeniran</dc:creator>
      <pubDate>Sun, 09 Mar 2025 13:07:45 +0000</pubDate>
      <link>https://dev.to/tuneshman/formik-react-part-3-validation-with-yup-streamlining-code-3a28</link>
      <guid>https://dev.to/tuneshman/formik-react-part-3-validation-with-yup-streamlining-code-3a28</guid>
      <description>&lt;p&gt;So far, we have &lt;a href="https://dev.to/tuneshman/formik-react-writing-cleaner-more-efficient-forms-fdj"&gt;managed the state of our order submission form&lt;/a&gt;, &lt;a href="https://dev.to/tuneshman/formik-react-from-basic-forms-to-a-scalable-reusable-approach-11il"&gt;validated our form fields&lt;/a&gt;, displayed error messages,handled form submission, and tracked visited fields. However, there is an even better way to carry out form validation, and that is through the use of a library known as &lt;a href="https://github.com/jquense/yup" rel="noopener noreferrer"&gt;yup&lt;/a&gt;. With &lt;code&gt;yup&lt;/code&gt;, we can eliminate manual interference from our &lt;code&gt;validate&lt;/code&gt; function.&lt;/p&gt;

&lt;h2&gt;
  
  
  Validation with yup
&lt;/h2&gt;

&lt;p&gt;We start by &lt;a href="https://www.npmjs.com/package/yup/v/1.0.0-alpha.3" rel="noopener noreferrer"&gt;installing yup&lt;/a&gt; and importing it into our &lt;code&gt;OrdersForm&lt;/code&gt; component. &lt;code&gt;yup&lt;/code&gt; allows us to define an object schema validation that can be assigned to a &lt;em&gt;yup object schema&lt;/em&gt;. This object will contain the validation rules for our form fields (&lt;code&gt;name&lt;/code&gt;, &lt;code&gt;email&lt;/code&gt;, and &lt;code&gt;quantity&lt;/code&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import "./order.css"
import { useFormik } from "formik"
import * as Yup from "yup"


const initialValues = {
  name: "",
  email: "",
  quantity: 0
}

const onSubmit = (values) =&amp;gt; {
  console.log(values)
}


const validationSchema = Yup.object({
  name: Yup.string().required("Name is required"),
  email: Yup.string().email("Invalid email format").required("Email is required"),
  quantity: Yup.number().required("Quantity is required")
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After this, the schema can be fed into the &lt;code&gt;useFormik&lt;/code&gt; hook replacing the &lt;code&gt;validate&lt;/code&gt; function that we previously used.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; const formik = useFormik({
    initialValues,
    onSubmit,
    validationSchema
  })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, we can remove our custom validation and our updated code becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import "./order.css"
import { useFormik } from "formik"
import * as Yup from "yup"


const initialValues = {
  name: "",
  email: "",
  quantity: 0
}

const onSubmit = (values) =&amp;gt; {
  console.log(values)
}


const validationSchema = Yup.object({
  name: Yup.string().required("Name is required"),
  email: Yup.string().email("Invalid email format").required("Email is required"),
  quantity: Yup.number().required("Quantity is required")
})


export const OrdersForm = () =&amp;gt; {
  const formik = useFormik({
    initialValues,
    onSubmit,
    validationSchema
  })


  return (
    &amp;lt;div className="form-container"&amp;gt;
      &amp;lt;h2&amp;gt;Order Submission Form&amp;lt;/h2&amp;gt;
      &amp;lt;form onSubmit={formik.handleSubmit}&amp;gt;
        &amp;lt;div className="form-group"&amp;gt;
          &amp;lt;label htmlFor='name'&amp;gt;Name:&amp;lt;/label&amp;gt;
          &amp;lt;input
            type="text"
            name="name"
            id='name'
            required
            onChange={formik.handleChange}
            onBlur={formik.handleBlur}
            value={formik.values.name}
          /&amp;gt;
          {formik.touched.name &amp;amp;&amp;amp; formik.errors.name ? (
            &amp;lt;div className="error"&amp;gt;{formik.errors.name}&amp;lt;/div&amp;gt;
          ) : null}
        &amp;lt;/div&amp;gt;

        &amp;lt;div className="form-group"&amp;gt;
          &amp;lt;label htmlFor='email'&amp;gt;Email:&amp;lt;/label&amp;gt;
          &amp;lt;input
            type="email"
            name="email"
            id='email'
            required
            onChange={formik.handleChange}
            onBlur={formik.handleBlur}
            value={formik.values.email}
          /&amp;gt;
          {formik.touched.email &amp;amp;&amp;amp; formik.errors.email ? (
            &amp;lt;div className="error"&amp;gt;{formik.errors.email}&amp;lt;/div&amp;gt;
          ) : null}
        &amp;lt;/div&amp;gt;

        &amp;lt;div className="form-group"&amp;gt;
          &amp;lt;label htmlFor='quantity'&amp;gt;Order Quantity:&amp;lt;/label&amp;gt;
          &amp;lt;input
            type="number"
            name="quantity"
            id='quantity'
            required
            onChange={formik.handleChange}
            onBlur={formik.handleBlur}
            value={formik.values.quantity}
          /&amp;gt;
          {formik.touched.quantity &amp;amp;&amp;amp; formik.errors.quantity ? (
            &amp;lt;div className="error"&amp;gt;{formik.errors.quantity}&amp;lt;/div&amp;gt;
          ) : null}
        &amp;lt;/div&amp;gt;

        &amp;lt;button type="submit" className="submit-btn"&amp;gt;
          Submit Order
        &amp;lt;/button&amp;gt;
      &amp;lt;/form&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Condensing logic and Refactoring for clarity
&lt;/h2&gt;

&lt;p&gt;Although our form works as it should at the moment, it is possible to optimize our code structure and minimize redundancy. If we closely examine our &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;email&lt;/code&gt;, and &lt;code&gt;quantity&lt;/code&gt; form fields, we see that several props (&lt;code&gt;onChange&lt;/code&gt;, &lt;code&gt;onBlur&lt;/code&gt;, and &lt;code&gt;value&lt;/code&gt;) are being repeated. This repetition violates the DRY &lt;em&gt;(Don't Repeat Yourself)&lt;/em&gt; principle. To improve efficiency, we can abstract the common configuration from each field in our form.&lt;/p&gt;

&lt;p&gt;A more streamlined approach is to use a helper method that dynamically applies these props as needed. Formik provides the &lt;code&gt;formik.getFieldProps()&lt;/code&gt; method, which simplifies this process by accepting the field's name as its argument and automatically handling its state and events.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import "./order.css"
import { useFormik } from "formik"
import * as Yup from "yup"


const initialValues = {
  name: "",
  email: "",
  quantity: 0
}

const onSubmit = (values) =&amp;gt; {
  console.log(values)
}

const validationSchema = Yup.object({
  name: Yup.string().required("Name is required"),
  email: Yup.string().email("Invalid email format").required("Email is required"),
  quantity: Yup.number().required("Quantity is required")
})


export const OrdersForm = () =&amp;gt; {
  const formik = useFormik({
    initialValues,
    onSubmit,
    validationSchema
  })

  return (
    &amp;lt;div className="form-container"&amp;gt;
      &amp;lt;h2&amp;gt;Order Submission Form&amp;lt;/h2&amp;gt;
      &amp;lt;form onSubmit={formik.handleSubmit}&amp;gt;
        &amp;lt;div className="form-group"&amp;gt;
          &amp;lt;label htmlFor='name'&amp;gt;Name:&amp;lt;/label&amp;gt;
          &amp;lt;input
            type="text"
            name="name"
            id='name'
            {...formik.getFieldProps('name')}
          /&amp;gt;
          {formik.touched.name &amp;amp;&amp;amp; formik.errors.name ? (
            &amp;lt;div className="error"&amp;gt;{formik.errors.name}&amp;lt;/div&amp;gt;
          ) : null}
        &amp;lt;/div&amp;gt;

        &amp;lt;div className="form-group"&amp;gt;
          &amp;lt;label htmlFor='email'&amp;gt;Email:&amp;lt;/label&amp;gt;
          &amp;lt;input
            type="email"
            name="email"
            id='email'
            {...formik.getFieldProps('email')}

          /&amp;gt;
          {formik.touched.email &amp;amp;&amp;amp; formik.errors.email ? (
            &amp;lt;div className="error"&amp;gt;{formik.errors.email}&amp;lt;/div&amp;gt;
          ) : null}
        &amp;lt;/div&amp;gt;

        &amp;lt;div className="form-group"&amp;gt;
          &amp;lt;label htmlFor='quantity'&amp;gt;Order Quantity:&amp;lt;/label&amp;gt;
          &amp;lt;input
            type="number"
            name="quantity"
            id='quantity'
            required
            {...formik.getFieldProps('quantity')}
          /&amp;gt;
          {formik.touched.quantity &amp;amp;&amp;amp; formik.errors.quantity ? (
            &amp;lt;div className="error"&amp;gt;{formik.errors.quantity}&amp;lt;/div&amp;gt;
          ) : null}
        &amp;lt;/div&amp;gt;

        &amp;lt;button type="submit" className="submit-btn"&amp;gt;
          Submit Order
        &amp;lt;/button&amp;gt;
      &amp;lt;/form&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, three lines of code in each form field is replaced with a single line. &lt;/p&gt;

&lt;p&gt;While the &lt;code&gt;formik.getFieldProps()&lt;/code&gt; helper method helps reduce redundant code, we still need to manually pass it to each input field. This means that if our form has ten fields, we would have to call &lt;code&gt;formik.getFieldProps()&lt;/code&gt; ten times, which can become repetitive.&lt;/p&gt;

&lt;p&gt;To simplify this further, Formik offers built-in components that help reduce verbosity and improve readability. These include the &lt;a href="https://formik.org/docs/api/formik" rel="noopener noreferrer"&gt;Formik&lt;/a&gt;, &lt;a href="https://formik.org/docs/api/form" rel="noopener noreferrer"&gt;Form&lt;/a&gt;, &lt;a href="https://formik.org/docs/api/field" rel="noopener noreferrer"&gt;Field&lt;/a&gt;, and &lt;a href="https://formik.org/docs/api/errormessage" rel="noopener noreferrer"&gt;ErrorMessage&lt;/a&gt; components, which streamline form handling and validation.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Formik&lt;/code&gt; component can serve as a replacement for the &lt;code&gt;useFormik&lt;/code&gt; hook in our code. Previously, we passed &lt;code&gt;initialValues&lt;/code&gt;, &lt;code&gt;onSubmit&lt;/code&gt;, and &lt;code&gt;validationSchema&lt;/code&gt; as an object argument within the &lt;code&gt;useFormik&lt;/code&gt; hook. Now, instead of using &lt;code&gt;useFormik&lt;/code&gt;, we will pass these configurations as props directly to the &lt;code&gt;Formik&lt;/code&gt; component.&lt;/p&gt;

&lt;p&gt;Before making this change, we need to update our imports by replacing &lt;code&gt;useFormik&lt;/code&gt; with &lt;code&gt;Formik&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import "./order.css"
import { Formik } from "formik"
import * as Yup from "yup"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we remove the &lt;code&gt;useFormik&lt;/code&gt; call and wrap our entire form with the &lt;code&gt;Formik&lt;/code&gt; component, passing the necessary props directly to it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import "./order.css"
import { Formik } from "formik"
import * as Yup from "yup"


const initialValues = {
  name: "",
  email: "",
  quantity: 0
}

const onSubmit = (values) =&amp;gt; {
  console.log(values)
}

const validationSchema = Yup.object({
  name: Yup.string().required("Name is required"),
  email: Yup.string().email("Invalid email format").required("Email is required"),
  quantity: Yup.number().required("Quantity is required")
})


export const OrdersForm = () =&amp;gt; {
  return (
    &amp;lt;Formik initialValues={initialValues} validationSchema={validationSchema} onSubmit={onSubmit}&amp;gt;
      &amp;lt;div className="form-container"&amp;gt;
        &amp;lt;h2&amp;gt;Order Submission Form&amp;lt;/h2&amp;gt;
        &amp;lt;form onSubmit={formik.handleSubmit}&amp;gt;
          &amp;lt;div className="form-group"&amp;gt;
            &amp;lt;label htmlFor='name'&amp;gt;Name:&amp;lt;/label&amp;gt;
            &amp;lt;input
              type="text"
              name="name"
              id='name'
              {...formik.getFieldProps('name')}
            /&amp;gt;
            {formik.touched.name &amp;amp;&amp;amp; formik.errors.name ? (
              &amp;lt;div className="error"&amp;gt;{formik.errors.name}&amp;lt;/div&amp;gt;
            ) : null}
          &amp;lt;/div&amp;gt;

          &amp;lt;div className="form-group"&amp;gt;
            &amp;lt;label htmlFor='email'&amp;gt;Email:&amp;lt;/label&amp;gt;
            &amp;lt;input
              type="email"
              name="email"
              id='email'
              {...formik.getFieldProps('email')}

            /&amp;gt;
            {formik.touched.email &amp;amp;&amp;amp; formik.errors.email ? (
              &amp;lt;div className="error"&amp;gt;{formik.errors.email}&amp;lt;/div&amp;gt;
            ) : null}
          &amp;lt;/div&amp;gt;

          &amp;lt;div className="form-group"&amp;gt;
            &amp;lt;label htmlFor='quantity'&amp;gt;Order Quantity:&amp;lt;/label&amp;gt;
            &amp;lt;input
              type="number"
              name="quantity"
              id='quantity'
              required
              {...formik.getFieldProps('quantity')}
            /&amp;gt;
            {formik.touched.quantity &amp;amp;&amp;amp; formik.errors.quantity ? (
              &amp;lt;div className="error"&amp;gt;{formik.errors.quantity}&amp;lt;/div&amp;gt;
            ) : null}
          &amp;lt;/div&amp;gt;

          &amp;lt;button type="submit" className="submit-btn"&amp;gt;
            Submit Order
          &amp;lt;/button&amp;gt;
        &amp;lt;/form&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/Formik&amp;gt;
  )
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We need to wrap the entire form with the Formik component to enable the use of additional components that simplify our form code. This allows us to introduce the Form component along with other necessary Formik components.&lt;/p&gt;

&lt;p&gt;Next, we import the Form component and replace the standard HTML &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt; element with it. Additionally, we remove the &lt;code&gt;onSubmit&lt;/code&gt; prop from the Form tag. Internally, the Form component acts as a wrapper around the native &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt; element, automatically integrating with Formik’s &lt;code&gt;handleSubmit&lt;/code&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import "./order.css"
import { Formik, Form } from "formik"
import * as Yup from "yup"


const initialValues = {
  name: "",
  email: "",
  quantity: 0
}

const onSubmit = (values) =&amp;gt; {
  console.log(values)
}

const validationSchema = Yup.object({
  name: Yup.string().required("Name is required"),
  email: Yup.string().email("Invalid email format").required("Email is required"),
  quantity: Yup.number().required("Quantity is required")
})


export const OrdersForm = () =&amp;gt; {
  return (
    &amp;lt;Formik initialValues={initialValues} validationSchema={validationSchema} onSubmit={onSubmit}&amp;gt;
      &amp;lt;div className="form-container"&amp;gt;
        &amp;lt;h2&amp;gt;Order Submission Form&amp;lt;/h2&amp;gt;
        &amp;lt;Form&amp;gt;
          &amp;lt;div className="form-group"&amp;gt;
            &amp;lt;label htmlFor='name'&amp;gt;Name:&amp;lt;/label&amp;gt;
            &amp;lt;input
              type="text"
              name="name"
              id='name'
              {...formik.getFieldProps('name')}
            /&amp;gt;
            {formik.touched.name &amp;amp;&amp;amp; formik.errors.name ? (
              &amp;lt;div className="error"&amp;gt;{formik.errors.name}&amp;lt;/div&amp;gt;
            ) : null}
          &amp;lt;/div&amp;gt;

          &amp;lt;div className="form-group"&amp;gt;
            &amp;lt;label htmlFor='email'&amp;gt;Email:&amp;lt;/label&amp;gt;
            &amp;lt;input
              type="email"
              name="email"
              id='email'
              {...formik.getFieldProps('email')}

            /&amp;gt;
            {formik.touched.email &amp;amp;&amp;amp; formik.errors.email ? (
              &amp;lt;div className="error"&amp;gt;{formik.errors.email}&amp;lt;/div&amp;gt;
            ) : null}
          &amp;lt;/div&amp;gt;

          &amp;lt;div className="form-group"&amp;gt;
            &amp;lt;label htmlFor='quantity'&amp;gt;Order Quantity:&amp;lt;/label&amp;gt;
            &amp;lt;input
              type="number"
              name="quantity"
              id='quantity'
              required
              {...formik.getFieldProps('quantity')}
            /&amp;gt;
            {formik.touched.quantity &amp;amp;&amp;amp; formik.errors.quantity ? (
              &amp;lt;div className="error"&amp;gt;{formik.errors.quantity}&amp;lt;/div&amp;gt;
            ) : null}
          &amp;lt;/div&amp;gt;

          &amp;lt;button type="submit" className="submit-btn"&amp;gt;
            Submit Order
          &amp;lt;/button&amp;gt;
        &amp;lt;/Form&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/Formik&amp;gt;
  )
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we introduce the &lt;code&gt;Field&lt;/code&gt; component to simplify form field handling. Currently, we are using the &lt;code&gt;getFieldProps&lt;/code&gt; helper method for each field, passing its corresponding name as an argument. However, we can further abstract this process to make our code cleaner and more efficient.&lt;/p&gt;

&lt;p&gt;To achieve this, we import &lt;code&gt;Field&lt;/code&gt; from Formik and replace our existing &lt;code&gt;&amp;lt;input&amp;gt;&lt;/code&gt; elements with the &lt;code&gt;Field&lt;/code&gt; component. This allows us to remove the &lt;code&gt;getFieldProps&lt;/code&gt; helper method from each field, streamlining our form implementation. Our updated code now looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import "./order.css"
import { Formik, Form, Field } from "formik"
import * as Yup from "yup"


const initialValues = {
  name: "",
  email: "",
  quantity: 0
}

const onSubmit = (values) =&amp;gt; {
  console.log(values)
}

const validationSchema = Yup.object({
  name: Yup.string().required("Name is required"),
  email: Yup.string().email("Invalid email format").required("Email is required"),
  quantity: Yup.number().required("Quantity is required")
})


export const OrdersForm = () =&amp;gt; {
  return (
    &amp;lt;Formik initialValues={initialValues} validationSchema={validationSchema} onSubmit={onSubmit}&amp;gt;
      &amp;lt;div className="form-container"&amp;gt;
        &amp;lt;h2&amp;gt;Order Submission Form&amp;lt;/h2&amp;gt;
        &amp;lt;Form&amp;gt;
          &amp;lt;div className="form-group"&amp;gt;
            &amp;lt;label htmlFor='name'&amp;gt;Name:&amp;lt;/label&amp;gt;
            &amp;lt;Field
              type="text"
              name="name"
              id='name'
            /&amp;gt;
            {formik.touched.name &amp;amp;&amp;amp; formik.errors.name ? (
              &amp;lt;div className="error"&amp;gt;{formik.errors.name}&amp;lt;/div&amp;gt;
            ) : null}
          &amp;lt;/div&amp;gt;

          &amp;lt;div className="form-group"&amp;gt;
            &amp;lt;label htmlFor='email'&amp;gt;Email:&amp;lt;/label&amp;gt;
            &amp;lt;Field
              type="email"
              name="email"
              id='email'
            /&amp;gt;
            {formik.touched.email &amp;amp;&amp;amp; formik.errors.email ? (
              &amp;lt;div className="error"&amp;gt;{formik.errors.email}&amp;lt;/div&amp;gt;
            ) : null}
          &amp;lt;/div&amp;gt;

          &amp;lt;div className="form-group"&amp;gt;
            &amp;lt;label htmlFor='quantity'&amp;gt;Order Quantity:&amp;lt;/label&amp;gt;
            &amp;lt;Field
              type="number"
              name="quantity"
              id='quantity'
              required
            /&amp;gt;
            {formik.touched.quantity &amp;amp;&amp;amp; formik.errors.quantity ? (
              &amp;lt;div className="error"&amp;gt;{formik.errors.quantity}&amp;lt;/div&amp;gt;
            ) : null}
          &amp;lt;/div&amp;gt;

          &amp;lt;button type="submit" className="submit-btn"&amp;gt;
            Submit Order
          &amp;lt;/button&amp;gt;
        &amp;lt;/Form&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/Formik&amp;gt;
  )
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our form errors are still referencing &lt;code&gt;formik&lt;/code&gt;, which was previously invoked through the &lt;code&gt;useFormik&lt;/code&gt; hook that we have now removed. To address this, we will use the &lt;code&gt;ErrorMessage&lt;/code&gt; component.&lt;/p&gt;

&lt;p&gt;Currently, we are manually checking whether a field has been visited and whether an error exists before displaying the error message. Since we repeat this process for all three form fields, it introduces unnecessary redundancy. The &lt;code&gt;ErrorMessage&lt;/code&gt; component helps eliminate this repetition.&lt;/p&gt;

&lt;p&gt;As with the other Formik components, we first import &lt;code&gt;ErrorMessage&lt;/code&gt; from Formik. Then, we replace our existing error messages with the ErrorMessage component, passing a &lt;code&gt;name&lt;/code&gt; prop that matches the corresponding Field component’s &lt;code&gt;name&lt;/code&gt; attribute.&lt;/p&gt;

&lt;p&gt;We've successfully reduced the amount of code significantly and introduced &lt;code&gt;yup&lt;/code&gt; for creating a validation schema. In the next article, we'll explore how to disable the submit button, load saved data, and reset the form data.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Formik &amp; React (Part 2): Enhancing Validation &amp; Error Handling</title>
      <dc:creator>Babatunde Adeniran</dc:creator>
      <pubDate>Mon, 03 Mar 2025 17:28:57 +0000</pubDate>
      <link>https://dev.to/tuneshman/formik-react-from-basic-forms-to-a-scalable-reusable-approach-11il</link>
      <guid>https://dev.to/tuneshman/formik-react-from-basic-forms-to-a-scalable-reusable-approach-11il</guid>
      <description>&lt;p&gt;In our &lt;a href="https://dev.to/tuneshman/formik-react-writing-cleaner-more-efficient-forms-fdj"&gt;previous article&lt;/a&gt;, we introduced Formik and explored how the &lt;code&gt;useFormik&lt;/code&gt; hook simplifies form state management, form submission, and validation. However, there are still a few crucial improvements needed to enhance the user experience.&lt;/p&gt;

&lt;p&gt;While we have implemented basic validation, there’s room for improvement. Currently, our form does not display error messages or keep track of fields that have already been visited—both of which are essential for a better user experience.&lt;/p&gt;

&lt;p&gt;In this article, we’ll address these issues and take our form handling to the next level.&lt;/p&gt;

&lt;p&gt;Let’s dive in!&lt;/p&gt;

&lt;h2&gt;
  
  
  Displaying Error Messages
&lt;/h2&gt;

&lt;p&gt;We already have a &lt;code&gt;validate&lt;/code&gt; function that checks for errors in our form fields (name, email, and quantity) and returns corresponding error messages based on our validation rules and conditions. However, we still need a way to display these error messages to the user.&lt;/p&gt;

&lt;p&gt;As we’ve established, the &lt;code&gt;formik&lt;/code&gt; object returned by the &lt;code&gt;useFormik&lt;/code&gt; hook contains various helper methods and useful properties for managing our form. So far, we’ve explored &lt;code&gt;initialValues&lt;/code&gt;, &lt;code&gt;onSubmit&lt;/code&gt;, and &lt;code&gt;validate&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;validate&lt;/code&gt; function helps us retrieve error messages, but how do we access them? Recall that &lt;code&gt;formik.values&lt;/code&gt; contains key-value pairs for our &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;email&lt;/code&gt;, and &lt;code&gt;quantity&lt;/code&gt; form fields. Similarly, Formik provides an &lt;code&gt;errors&lt;/code&gt; property, which follows the same structure as &lt;code&gt;formik.values&lt;/code&gt;—it’s an object with key-value pairs for our form fields, holding their corresponding validation errors.&lt;/p&gt;

&lt;p&gt;Let’s log &lt;code&gt;formik.errors&lt;/code&gt; to the console and see what it contains.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  const formik = useFormik({
    initialValues,
    onSubmit,
    validate
  })
  console.log("Form errors", formik.errors)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Typically, &lt;code&gt;formik.errors&lt;/code&gt; returns an empty object when the page mounts.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb20aibv1gsdt6p9kv8m4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb20aibv1gsdt6p9kv8m4.png" alt=" raw `formik.errors` endraw " width="800" height="368"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;However, when we alter the &lt;code&gt;initialValues&lt;/code&gt;, the &lt;code&gt;errors&lt;/code&gt; object is populated with keys that are similar to that of &lt;code&gt;formik.values&lt;/code&gt; from our &lt;a href="https://dev.to/tuneshman/formik-react-writing-cleaner-more-efficient-forms-fdj"&gt;previous article&lt;/a&gt;. We would also see that the value of each error field is the error message we defined in our &lt;code&gt;validate&lt;/code&gt; function. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuw5robpfq8so3fx2tnx3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuw5robpfq8so3fx2tnx3.png" alt=" raw `formik.errors` endraw " width="800" height="412"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What Formik does under the hood is to run the &lt;code&gt;validate&lt;/code&gt; function when the form field changes. The &lt;code&gt;formik.errors&lt;/code&gt; object is then populated with error messages based on the rules outlined in the &lt;code&gt;validate&lt;/code&gt; function. &lt;/p&gt;

&lt;p&gt;Next, we conditionally render error messages from the &lt;code&gt;formik.errors&lt;/code&gt; object in &lt;code&gt;JSX&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import "./order.css"
import { useFormik } from "formik"



const initialValues = {
  name: "",
  email: "",
  quantity: 0
}

const onSubmit = (values) =&amp;gt; {
  console.log(values)
}
const validate = (values) =&amp;gt; {
  const errors = {}
  if (!values.name) {
    errors.name = "Name is required"
  }
  if (!values.email) {
    errors.email = "Email is required"
  } else if (
    !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(values.email)
  ) {
    errors.email = "Invalid email address"
  }
  if (!values.quantity) {
    errors.quantity = "Quantity is required"
  }
  return errors
}

export const OrdersForm = () =&amp;gt; {
  const formik = useFormik({
    initialValues,
    onSubmit,
    validate
  })

  return (
    &amp;lt;div className="form-container"&amp;gt;
      &amp;lt;h2&amp;gt;Order Submission Form&amp;lt;/h2&amp;gt;
      &amp;lt;form onSubmit={formik.handleSubmit}&amp;gt;
        &amp;lt;div className="form-group"&amp;gt;
          &amp;lt;label htmlFor='name'&amp;gt;Name:&amp;lt;/label&amp;gt;
          &amp;lt;input
            type="text"
            name="name"
            id='name'
            required
            onChange={formik.handleChange}
            value={formik.values.name}
          /&amp;gt;
          {formik.errors.name ? (
            &amp;lt;div className="error"&amp;gt;{formik.errors.name}&amp;lt;/div&amp;gt;
          ) : null}
        &amp;lt;/div&amp;gt;

        &amp;lt;div className="form-group"&amp;gt;
          &amp;lt;label htmlFor='email'&amp;gt;Email:&amp;lt;/label&amp;gt;
          &amp;lt;input
            type="email"
            name="email"
            id='email'
            required
            onChange={formik.handleChange}
            value={formik.values.email}
          /&amp;gt;
          {formik.errors.email ? (
            &amp;lt;div className="error"&amp;gt;{formik.errors.email}&amp;lt;/div&amp;gt;
          ) : null}
        &amp;lt;/div&amp;gt;

        &amp;lt;div className="form-group"&amp;gt;
          &amp;lt;label htmlFor='quantity'&amp;gt;Order Quantity:&amp;lt;/label&amp;gt;
          &amp;lt;input
            type="number"
            name="quantity"
            id='quantity'
            required
            onChange={formik.handleChange}
            value={formik.values.quantity}
          /&amp;gt;
          {formik.errors.quantity ? (
            &amp;lt;div className="error"&amp;gt;{formik.errors.quantity}&amp;lt;/div&amp;gt;
          ) : null}
        &amp;lt;/div&amp;gt;

        &amp;lt;button type="submit" className="submit-btn"&amp;gt;
          Submit Order
        &amp;lt;/button&amp;gt;
      &amp;lt;/form&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We would also add an &lt;code&gt;error class&lt;/code&gt; to our &lt;code&gt;order.css&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.form-container {
    width: 350px;
    margin: 40px auto;
    padding: 20px;
    border: 1px solid #ccc;
    border-radius: 8px;
    background-color: #f9f9f9;
    text-align: center;
  }

  h2 {
    margin-bottom: 20px;
  }

  .form-group {
    margin-bottom: 15px;
    text-align: left;
  }

  label {
    display: block;
    font-weight: bold;
    margin-bottom: 5px;
  }

  input {
    width: 100%;
    padding: 8px;
    border: 1px solid #ccc;
    border-radius: 4px;
  }

  .submit-btn {
    width: 100%;
    padding: 10px;
    background-color: #007bff;
    color: white;
    border: none;
    border-radius: 4px;
    font-size: 16px;
    cursor: pointer;
  }

  .submit-btn:hover {
    background-color: #0056b3;
  }

  .error {
    color: red;
    margin-top: 5px;
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy68ra9p068owfn6qtewu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy68ra9p068owfn6qtewu.png" alt="Validation errors" width="800" height="297"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Although the error messages are displayed correctly, there is still an issue to fix. Currently, error messages for all three fields appear even when we interact with just one input field. This is not an ideal user experience, let's correct it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Visited Fields
&lt;/h2&gt;

&lt;p&gt;Although the error messages are visible to users, we have to keep track of visited fields so that error messages are not displayed on inputs or fields that are yet to be visited. As it stands, every keyboard event triggers the &lt;code&gt;validate&lt;/code&gt; function to be called and this means the &lt;code&gt;form.errors&lt;/code&gt; object containing the error messages for name, email, and quantity will be populated at every instance. We only want to display error messages for the field the user has interacted with, and it even makes more sense to display error messages for a field after the user has finished typing in that field. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;onBlur&lt;/code&gt; prop tracks which fields have been visited. Adding it to our input fields will resolve this issue. Formik also provides a helper method called &lt;code&gt;handleBlur&lt;/code&gt;, which we pass to the &lt;code&gt;onBlur&lt;/code&gt; prop.&lt;/p&gt;

&lt;p&gt;Formik saves the details of already visited fields in the &lt;code&gt;touched&lt;/code&gt; object. The &lt;code&gt;touched&lt;/code&gt; object has a similar structure to the &lt;code&gt;formik.errors&lt;/code&gt; and &lt;code&gt;formik.values&lt;/code&gt; objects.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import "./order.css"
import { useFormik } from "formik"



const initialValues = {
  name: "",
  email: "",
  quantity: 0
}

const onSubmit = (values) =&amp;gt; {
  console.log(values)
}
const validate = (values) =&amp;gt; {
  const errors = {}
  if (!values.name) {
    errors.name = "Name is required"
  }
  if (!values.email) {
    errors.email = "Email is required"
  } else if (
    !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(values.email)
  ) {
    errors.email = "Invalid email address"
  }
  if (!values.quantity) {
    errors.quantity = "Quantity is required"
  }
  return errors
}

export const OrdersForm = () =&amp;gt; {
  const formik = useFormik({
    initialValues,
    onSubmit,
    validate
  })

  console.log("Visited form fields", formik.touched)

  return (
    &amp;lt;div className="form-container"&amp;gt;
      &amp;lt;h2&amp;gt;Order Submission Form&amp;lt;/h2&amp;gt;
      &amp;lt;form onSubmit={formik.handleSubmit}&amp;gt;
        &amp;lt;div className="form-group"&amp;gt;
          &amp;lt;label htmlFor='name'&amp;gt;Name:&amp;lt;/label&amp;gt;
          &amp;lt;input
            type="text"
            name="name"
            id='name'
            required
            onChange={formik.handleChange}
            onBlur={formik.handleBlur}
            value={formik.values.name}
          /&amp;gt;
          {formik.errors.name ? (
            &amp;lt;div className="error"&amp;gt;{formik.errors.name}&amp;lt;/div&amp;gt;
          ) : null}
        &amp;lt;/div&amp;gt;

        &amp;lt;div className="form-group"&amp;gt;
          &amp;lt;label htmlFor='email'&amp;gt;Email:&amp;lt;/label&amp;gt;
          &amp;lt;input
            type="email"
            name="email"
            id='email'
            required
            onChange={formik.handleChange}
            onBlur={formik.handleBlur}
            value={formik.values.email}
          /&amp;gt;
          {formik.errors.email ? (
            &amp;lt;div className="error"&amp;gt;{formik.errors.email}&amp;lt;/div&amp;gt;
          ) : null}
        &amp;lt;/div&amp;gt;

        &amp;lt;div className="form-group"&amp;gt;
          &amp;lt;label htmlFor='quantity'&amp;gt;Order Quantity:&amp;lt;/label&amp;gt;
          &amp;lt;input
            type="number"
            name="quantity"
            id='quantity'
            required
            onChange={formik.handleChange}
            onBlur={formik.handleBlur}
            value={formik.values.quantity}
          /&amp;gt;
          {formik.errors.quantity ? (
            &amp;lt;div className="error"&amp;gt;{formik.errors.quantity}&amp;lt;/div&amp;gt;
          ) : null}
        &amp;lt;/div&amp;gt;

        &amp;lt;button type="submit" className="submit-btn"&amp;gt;
          Submit Order
        &amp;lt;/button&amp;gt;
      &amp;lt;/form&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we check the logs for the visited fields on page load, we should see an empty object indicating that none of the fields have been visited.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5dunu2ujdc6yniwocqkf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5dunu2ujdc6yniwocqkf.png" alt="Visited fields" width="800" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let's click in and out of the &lt;code&gt;email&lt;/code&gt; field&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd323dkd08metuqsooil4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd323dkd08metuqsooil4.png" alt="Touched field" width="800" height="412"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can see that the &lt;code&gt;touched&lt;/code&gt; object is no longer empty—the &lt;code&gt;email&lt;/code&gt; field has been marked as visited. The same applies to the &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;quantity&lt;/code&gt; fields when touched. The details of the &lt;code&gt;formik.touched&lt;/code&gt; object can then be used to dynamically render error messages.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import "./order.css"
import { useFormik } from "formik"



const initialValues = {
  name: "",
  email: "",
  quantity: 0
}

const onSubmit = (values) =&amp;gt; {
  console.log(values)
}
const validate = (values) =&amp;gt; {
  const errors = {}
  if (!values.name) {
    errors.name = "Name is required"
  }
  if (!values.email) {
    errors.email = "Email is required"
  } else if (
    !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(values.email)
  ) {
    errors.email = "Invalid email address"
  }
  if (!values.quantity) {
    errors.quantity = "Quantity is required"
  }
  return errors
}

export const OrdersForm = () =&amp;gt; {
  const formik = useFormik({
    initialValues,
    onSubmit,
    validate
  })


  return (
    &amp;lt;div className="form-container"&amp;gt;
      &amp;lt;h2&amp;gt;Order Submission Form&amp;lt;/h2&amp;gt;
      &amp;lt;form onSubmit={formik.handleSubmit}&amp;gt;
        &amp;lt;div className="form-group"&amp;gt;
          &amp;lt;label htmlFor='name'&amp;gt;Name:&amp;lt;/label&amp;gt;
          &amp;lt;input
            type="text"
            name="name"
            id='name'
            required
            onChange={formik.handleChange}
            onBlur={formik.handleBlur}
            value={formik.values.name}
          /&amp;gt;
          {formik.touched.name &amp;amp;&amp;amp; formik.errors.name ? (
            &amp;lt;div className="error"&amp;gt;{formik.errors.name}&amp;lt;/div&amp;gt;
          ) : null}
        &amp;lt;/div&amp;gt;

        &amp;lt;div className="form-group"&amp;gt;
          &amp;lt;label htmlFor='email'&amp;gt;Email:&amp;lt;/label&amp;gt;
          &amp;lt;input
            type="email"
            name="email"
            id='email'
            required
            onChange={formik.handleChange}
            onBlur={formik.handleBlur}
            value={formik.values.email}
          /&amp;gt;
          {formik.touched.email &amp;amp;&amp;amp; formik.errors.email ? (
            &amp;lt;div className="error"&amp;gt;{formik.errors.email}&amp;lt;/div&amp;gt;
          ) : null}
        &amp;lt;/div&amp;gt;

        &amp;lt;div className="form-group"&amp;gt;
          &amp;lt;label htmlFor='quantity'&amp;gt;Order Quantity:&amp;lt;/label&amp;gt;
          &amp;lt;input
            type="number"
            name="quantity"
            id='quantity'
            required
            onChange={formik.handleChange}
            onBlur={formik.handleBlur}
            value={formik.values.quantity}
          /&amp;gt;
          {formik.touched.quantity &amp;amp;&amp;amp; formik.errors.quantity ? (
            &amp;lt;div className="error"&amp;gt;{formik.errors.quantity}&amp;lt;/div&amp;gt;
          ) : null}
        &amp;lt;/div&amp;gt;

        &amp;lt;button type="submit" className="submit-btn"&amp;gt;
          Submit Order
        &amp;lt;/button&amp;gt;
      &amp;lt;/form&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are other ways we can define our form validation rules. We will look at that next. &lt;/p&gt;

</description>
    </item>
    <item>
      <title>Formik &amp; React: Writing Cleaner, More Efficient Forms</title>
      <dc:creator>Babatunde Adeniran</dc:creator>
      <pubDate>Sat, 01 Mar 2025 22:59:28 +0000</pubDate>
      <link>https://dev.to/tuneshman/formik-react-writing-cleaner-more-efficient-forms-fdj</link>
      <guid>https://dev.to/tuneshman/formik-react-writing-cleaner-more-efficient-forms-fdj</guid>
      <description>&lt;p&gt;The importance of forms in business applications cannot be overemphasized. We use forms to accomplish many tasks and facilitate various processes, such as user registration, user sign-in, feedback collection, and order creation. Because forms are crucial to most web interactions, it is essential to ensure a seamless user experience through effective development.&lt;/p&gt;

&lt;p&gt;When creating forms, developers take on numerous responsibilities, including field validation, efficient handling of form data, comprehensive error management, and an optimized form submission process.&lt;/p&gt;

&lt;p&gt;In this article, I will explain how we can achieve all these with Formik, a highly useful library for managing forms in React and React Native.&lt;/p&gt;

&lt;p&gt;Formik simplifies form handling by managing form data, validation, submission, and error messages efficiently. While &lt;code&gt;React&lt;/code&gt; provides multiple approaches to handling forms, Formik abstracts the complex and tedious parts, allowing developers to build advanced forms with ease. It is both scalable and performant, making it an excellent choice for form management in React applications.&lt;/p&gt;

&lt;p&gt;We start with a simple presentational &lt;code&gt;React.js&lt;/code&gt; form component without any functionality. The goal is to implement form state management, handle form submission, validate inputs, and display error messages. The form is designed for submitting orders for an imaginary company, Love &amp;amp; Light Pizzas Ltd. The order submission form has three fields: &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;email&lt;/code&gt;, and &lt;code&gt;order quantity&lt;/code&gt;. It will also include a submit button.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import "./order.css"

export const OrdersForm = () =&amp;gt; {
  return (
    &amp;lt;div className="form-container"&amp;gt;
      &amp;lt;h2&amp;gt;Order Submission Form&amp;lt;/h2&amp;gt;
      &amp;lt;form &amp;gt;
        &amp;lt;div className="form-group"&amp;gt;
          &amp;lt;label htmlFor='name'&amp;gt;Name:&amp;lt;/label&amp;gt;
          &amp;lt;input
            type="text"
            name="name"
            id='name'
            required
          /&amp;gt;
        &amp;lt;/div&amp;gt;

        &amp;lt;div className="form-group"&amp;gt;
          &amp;lt;label htmlFor='email'&amp;gt;Email:&amp;lt;/label&amp;gt;
          &amp;lt;input
            type="email"
            name="email"
            id='email'
            required
          /&amp;gt;
        &amp;lt;/div&amp;gt;

        &amp;lt;div className="form-group"&amp;gt;
          &amp;lt;label htmlFor='quantity'&amp;gt;Order Quantity:&amp;lt;/label&amp;gt;
          &amp;lt;input
            type="number"
            name="quantity"
            id='quantity'
            required
          /&amp;gt;
        &amp;lt;/div&amp;gt;

        &amp;lt;button type="submit" className="submit-btn"&amp;gt;
          Submit Order
        &amp;lt;/button&amp;gt;
      &amp;lt;/form&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.form-container {
    width: 350px;
    margin: 40px auto;
    padding: 20px;
    border: 1px solid #ccc;
    border-radius: 8px;
    background-color: #f9f9f9;
    text-align: center;
  }

  h2 {
    margin-bottom: 20px;
  }

  .form-group {
    margin-bottom: 15px;
    text-align: left;
  }

  label {
    display: block;
    font-weight: bold;
    margin-bottom: 5px;
  }

  input {
    width: 100%;
    padding: 8px;
    border: 1px solid #ccc;
    border-radius: 4px;
  }

  .submit-btn {
    width: 100%;
    padding: 10px;
    background-color: #007bff;
    color: white;
    border: none;
    border-radius: 4px;
    font-size: 16px;
    cursor: pointer;
  }

  .submit-btn:hover {
    background-color: #0056b3;
  }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After installing Formik, our next step is to import the &lt;code&gt;useFormik&lt;/code&gt; hook which the library provides. Since hooks are simply functions, they need to be called within the component. The useFormik hook returns an object containing a variety of methods and properties that can be used within the form. With this Formik object, it becomes easier to achieve our aim of handling form submission, managing the state of the form, and validating input error messages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;FORM STATE MANAGEMENT&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We already know that state is an object that determines how a component renders and behaves. At the moment, our form component is an uncontrolled component, which means it is a traditional HTML form input whose value we cannot manage directly. Our order form has three fields, but as it stands, we are not keeping track of the form field values. When we enter something into the input fields, the field value changes. In &lt;code&gt;React&lt;/code&gt;, when there are changes in values, we use state variables to keep track of those changes. So, we need state variables for the &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;email&lt;/code&gt;, and &lt;code&gt;order quantity&lt;/code&gt; inputs. Together, these are referred to as the form state.&lt;/p&gt;

&lt;p&gt;In Formik, the form state is an object that maintains the value of individual form fields. Therefore, it is crucial to understand how Formik helps manage the form state when form field values change.&lt;/p&gt;

&lt;p&gt;We first pass a property called &lt;code&gt;initial values&lt;/code&gt; in the object configuration. It is an object that contains the initial values of our form fields. The properties of the &lt;code&gt;initialValues&lt;/code&gt; object must correspond with the name attribute of our form inputs. &lt;/p&gt;

&lt;p&gt;To track changes in individual form inputs, we add an &lt;code&gt;onChange&lt;/code&gt; and &lt;code&gt;value&lt;/code&gt; prop to each input. This is similar to basic form handling in &lt;code&gt;React.js&lt;/code&gt;, where we assign the state property as the input’s value and handle the &lt;code&gt;onChange&lt;/code&gt; event by creating an event handler. With Formik, we use &lt;code&gt;formik.handleChange&lt;/code&gt; to handle this event. Additionally, we can sync the value of the input with the state property by accessing &lt;code&gt;formik.values.nameAttribute&lt;/code&gt;, as shown below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import "./order.css"
import { useFormik } from "formik"

export const OrdersForm = () =&amp;gt; {
  const formik = useFormik({
    initialValues: {
      name: "",
      email: "",
      quantity: 0
    }
  })
  return (
    &amp;lt;div className="form-container"&amp;gt;
      &amp;lt;h2&amp;gt;Order Submission Form&amp;lt;/h2&amp;gt;
      &amp;lt;form &amp;gt;
        &amp;lt;div className="form-group"&amp;gt;
          &amp;lt;label htmlFor='name'&amp;gt;Name:&amp;lt;/label&amp;gt;
          &amp;lt;input
            type="text"
            name="name"
            id='name'
            required
            onChange={formik.handleChange}
            value={formik.values.name}
          /&amp;gt;
        &amp;lt;/div&amp;gt;

        &amp;lt;div className="form-group"&amp;gt;
          &amp;lt;label htmlFor='email'&amp;gt;Email:&amp;lt;/label&amp;gt;
          &amp;lt;input
            type="email"
            name="email"
            id='email'
            required
            onChange={formik.handleChange}
            value={formik.values.email}
          /&amp;gt;
        &amp;lt;/div&amp;gt;

        &amp;lt;div className="form-group"&amp;gt;
          &amp;lt;label htmlFor='quantity'&amp;gt;Order Quantity:&amp;lt;/label&amp;gt;
          &amp;lt;input
            type="number"
            name="quantity"
            id='quantity'
            required
            onChange={formik.handleChange}
            value={formik.values.quantity}
          /&amp;gt;
        &amp;lt;/div&amp;gt;

        &amp;lt;button type="submit" className="submit-btn"&amp;gt;
          Submit Order
        &amp;lt;/button&amp;gt;
      &amp;lt;/form&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When we log the &lt;code&gt;formik.values&lt;/code&gt; object in the console, we would see that it is structured such that the keys are the name attributes of the form fields, and as we type into individual fields, the changes are reflected in each input value. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgu5bfkq6t0lg7ndkn3ir.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgu5bfkq6t0lg7ndkn3ir.png" alt="Log result of form input values" width="800" height="366"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Facg0g9y1r186rwl10131.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Facg0g9y1r186rwl10131.png" alt="Log result of form input values" width="800" height="434"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We see that at every point in time, &lt;code&gt;formik.values&lt;/code&gt; reflects the application state. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HANDLING FORM SUBMISSION&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So far, we have discussed how the form values are tracked and extracted. However, we have not yet covered how the values are handled when the user clicks the submit button. There are two steps involved in form submission with Formik.&lt;/p&gt;

&lt;p&gt;The first step is to specify the onSubmit handler on the &lt;code&gt;&amp;lt;form&amp;gt;&lt;/code&gt; tag, just as we listened to change events on form inputs using the &lt;code&gt;onChange&lt;/code&gt; handler. Typically, the Formik helper method we previously defined provides a method for handling form submission, called the &lt;code&gt;handleSubmit&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;For the second step, we return to our &lt;code&gt;useFormik&lt;/code&gt; hook configuration and pass a second property called &lt;code&gt;onSubmit&lt;/code&gt;. By default, the onSubmit method receives the state of the form as its argument. The &lt;code&gt;values&lt;/code&gt; argument in the &lt;code&gt;onSubmit&lt;/code&gt; method is a reference to &lt;code&gt;formik.values&lt;/code&gt;. The &lt;code&gt;onSubmit&lt;/code&gt; method is triggered as soon as the submit button is clicked.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import "./order.css"
import { useFormik } from "formik"

export const OrdersForm = () =&amp;gt; {
  const formik = useFormik({
    initialValues: {
      name: "",
      email: "",
      quantity: 0
    },
    onSubmit: (values) =&amp;gt; {
      console.log(values, "Form data")
    }
  })

  return (
    &amp;lt;div className="form-container"&amp;gt;
      &amp;lt;h2&amp;gt;Order Submission Form&amp;lt;/h2&amp;gt;
      &amp;lt;form onSubmit={formik.handleSubmit}&amp;gt;
        &amp;lt;div className="form-group"&amp;gt;
          &amp;lt;label htmlFor='name'&amp;gt;Name:&amp;lt;/label&amp;gt;
          &amp;lt;input
            type="text"
            name="name"
            id='name'
            required
            onChange={formik.handleChange}
            value={formik.values.name}
          /&amp;gt;
        &amp;lt;/div&amp;gt;

        &amp;lt;div className="form-group"&amp;gt;
          &amp;lt;label htmlFor='email'&amp;gt;Email:&amp;lt;/label&amp;gt;
          &amp;lt;input
            type="email"
            name="email"
            id='email'
            required
            onChange={formik.handleChange}
            value={formik.values.email}
          /&amp;gt;
        &amp;lt;/div&amp;gt;

        &amp;lt;div className="form-group"&amp;gt;
          &amp;lt;label htmlFor='quantity'&amp;gt;Order Quantity:&amp;lt;/label&amp;gt;
          &amp;lt;input
            type="number"
            name="quantity"
            id='quantity'
            required
            onChange={formik.handleChange}
            value={formik.values.quantity}
          /&amp;gt;
        &amp;lt;/div&amp;gt;

        &amp;lt;button type="submit" className="submit-btn"&amp;gt;
          Submit Order
        &amp;lt;/button&amp;gt;
      &amp;lt;/form&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn287a9sl636golr37kbc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn287a9sl636golr37kbc.png" alt="Form submission values" width="800" height="402"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We see that the logs after the submit button is clicked are in sync with the content of the form. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HANDLING FORM VALIDATION&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As it stands, we can manage the state of our order form and submit data by clicking a button. However, we have not yet validated our form fields to filter form values based on established rules.&lt;/p&gt;

&lt;p&gt;With Formik, we can define a validation function assigned to the &lt;code&gt;validate&lt;/code&gt; property, which will be our third property in the &lt;code&gt;useFormik&lt;/code&gt; hook configuration. Like the &lt;code&gt;onSubmit&lt;/code&gt; property, the &lt;code&gt;validate&lt;/code&gt; function receives the &lt;code&gt;values&lt;/code&gt; object as an argument by default. There are certain conditions that the &lt;code&gt;validate&lt;/code&gt; function must satisfy, one of these is that it must return an object. We assign this object to a variable and return it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  validate: (values) =&amp;gt; {
      const errors: any = {}
      return errors
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Another condition that must be fulfilled is that the keys of the &lt;code&gt;values&lt;/code&gt; and &lt;code&gt;errors&lt;/code&gt; objects must be in sync. Currently, we have &lt;code&gt;values.name&lt;/code&gt;, &lt;code&gt;values.email&lt;/code&gt;, and &lt;code&gt;values.quantity&lt;/code&gt;. Similarly, we will have &lt;code&gt;errors.name&lt;/code&gt;, &lt;code&gt;errors.email&lt;/code&gt;, and &lt;code&gt;errors.quantity&lt;/code&gt;. Additionally, the values of the keys defined in the errors object must be strings that convey the correct error message.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import "./order.css"
import { useFormik } from "formik"

export const OrdersForm = () =&amp;gt; {
  const formik = useFormik({
    initialValues: {
      name: "",
      email: "",
      quantity: 0
    },
    onSubmit: (values) =&amp;gt; {
      console.log(values, "Form data")
    },
    validate: (values) =&amp;gt; {
      const errors = {}
      if (!values.name) {
        errors.name = "Name is required"
      }
      if (!values.email) {
        errors.email = "Email is required"
      } else if (
        !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(values.email)
      ) {
        errors.email = "Invalid email address"
      }
      if (!values.quantity) {
        errors.quantity = "Quantity is required"
      }
      return errors
    }
  })

  return (
    &amp;lt;div className="form-container"&amp;gt;
      &amp;lt;h2&amp;gt;Order Submission Form&amp;lt;/h2&amp;gt;
      &amp;lt;form onSubmit={formik.handleSubmit}&amp;gt;
        &amp;lt;div className="form-group"&amp;gt;
          &amp;lt;label htmlFor='name'&amp;gt;Name:&amp;lt;/label&amp;gt;
          &amp;lt;input
            type="text"
            name="name"
            id='name'
            required
            onChange={formik.handleChange}
            value={formik.values.name}
          /&amp;gt;
        &amp;lt;/div&amp;gt;

        &amp;lt;div className="form-group"&amp;gt;
          &amp;lt;label htmlFor='email'&amp;gt;Email:&amp;lt;/label&amp;gt;
          &amp;lt;input
            type="email"
            name="email"
            id='email'
            required
            onChange={formik.handleChange}
            value={formik.values.email}
          /&amp;gt;
        &amp;lt;/div&amp;gt;

        &amp;lt;div className="form-group"&amp;gt;
          &amp;lt;label htmlFor='quantity'&amp;gt;Order Quantity:&amp;lt;/label&amp;gt;
          &amp;lt;input
            type="number"
            name="quantity"
            id='quantity'
            required
            onChange={formik.handleChange}
            value={formik.values.quantity}
          /&amp;gt;
        &amp;lt;/div&amp;gt;

        &amp;lt;button type="submit" className="submit-btn"&amp;gt;
          Submit Order
        &amp;lt;/button&amp;gt;
      &amp;lt;/form&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's refactor this code to improve the readability of the &lt;code&gt;userFormik&lt;/code&gt; hook.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import "./order.css"
import { useFormik } from "formik"



const initialValues = {
  name: "",
  email: "",
  quantity: 0
}

const onSubmit = (values) =&amp;gt; {
  console.log(values, "Form data")
}
const validate = (values) =&amp;gt; {
  const errors = {}
  if (!values.name) {
    errors.name = "Name is required"
  }
  if (!values.email) {
    errors.email = "Email is required"
  } else if (
    !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(values.email)
  ) {
    errors.email = "Invalid email address"
  }
  if (!values.quantity) {
    errors.quantity = "Quantity is required"
  }
  return errors
}

export const OrdersForm = () =&amp;gt; {
  const formik = useFormik({
    initialValues,
    onSubmit,
    validate

  })

  return (
    &amp;lt;div className="form-container"&amp;gt;
      &amp;lt;h2&amp;gt;Order Submission Form&amp;lt;/h2&amp;gt;
      &amp;lt;form onSubmit={formik.handleSubmit}&amp;gt;
        &amp;lt;div className="form-group"&amp;gt;
          &amp;lt;label htmlFor='name'&amp;gt;Name:&amp;lt;/label&amp;gt;
          &amp;lt;input
            type="text"
            name="name"
            id='name'
            required
            onChange={formik.handleChange}
            value={formik.values.name}
          /&amp;gt;
        &amp;lt;/div&amp;gt;

        &amp;lt;div className="form-group"&amp;gt;
          &amp;lt;label htmlFor='email'&amp;gt;Email:&amp;lt;/label&amp;gt;
          &amp;lt;input
            type="email"
            name="email"
            id='email'
            required
            onChange={formik.handleChange}
            value={formik.values.email}
          /&amp;gt;
        &amp;lt;/div&amp;gt;

        &amp;lt;div className="form-group"&amp;gt;
          &amp;lt;label htmlFor='quantity'&amp;gt;Order Quantity:&amp;lt;/label&amp;gt;
          &amp;lt;input
            type="number"
            name="quantity"
            id='quantity'
            required
            onChange={formik.handleChange}
            value={formik.values.quantity}
          /&amp;gt;
        &amp;lt;/div&amp;gt;

        &amp;lt;button type="submit" className="submit-btn"&amp;gt;
          Submit Order
        &amp;lt;/button&amp;gt;
      &amp;lt;/form&amp;gt;
    &amp;lt;/div&amp;gt;
  )
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the next article, we will cover how to display these error messages, identify visited fields, define a validation schema with &lt;code&gt;Yup&lt;/code&gt;, and reduce boilerplate to improve reusability.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
