With the form fields and validations in place, we're ready to manage form submission. In this lesson, we will delve into Formik's approach to handling submissions and explore how we can utilize this to place an order.
Submission handling in Formik
Handling form submission in Formik involves multiple stages, from pre-submit actions to validation and actual submission handling. Let's break it down:
Pre-Submit Phase
Before initiating the submission process, Formik undertakes several preparatory steps:
-
Touching Fields: All fields within the form are "touched" to ensure they've been interacted with, utilizing the provided initialValues
as a baseline for comparison.
-
Setting isSubmitting
to true
: This flag indicates that the form is in the process of being submitted.
-
Incrementing submitCount
: Keeping track of the number of times the form has been submitted.
Validation Stage
The validation stage primarily involves the following steps:
-
Setting isValidating
to true
: Signaling that the validation process is underway.
-
Running Validations: This involves executing field-level validations defined by the validationSchema
. These validations occur asynchronously and their results are deeply merged.
-
Error Check: Upon validation completion, Formik checks if there are any errors:
- Errors Found: If errors exist, the submission is aborted.
isValidating
is set to false
, errors
object is set, and isSubmitting
is set to false
to halt the submission.
- No Errors: If the validation passes without errors, the process moves to the submission phase.
Submission Phase
The final step involves handling the submission of the form:
-
Executing the Submission Handler: The form invokes the designated submission handler, handler passed to onSubmit
prop, to process the form values. This action takes place within this phase. The onSubmit
callback function receives two parameters:
values
: This parameter contains the current values of all the form fields at the time of submission. It represents the data that the user has entered into the form.
formikBag
: The formikBag
is an object provided by Formik, and it includes a subset of injected props and methods. Specifically, it contains all the methods with names that start with set<Thing>
and resetForm
, as well as any props that were passed to the wrapped component.
-
Checking for a Promise:
- Handling Promise: If the submit handler returns a promise, Formik awaits resolution or rejection of the promise returned by the submission handler. Upon completion,
setSubmitting
is set to false
to finalize the submission cycle.
- Handling Synchronous Submission: In cases where the submission handler is synchronous, it's crucial to manually call
setSubmitting(false)
to conclude the submission cycle. Formik won't automatically handle this for synchronous submissions.
Managing form submission and order creation in SmileCart
In SmileCart, handling form submission involves creating an order with the entered form values. This operation is facilitated by sending a POST request to /orders
, using the form data as the payload. To initiate this functionality, we'll set up an API connector file named orders.js
within the src/apis
directory.
Within this file let's define the create
method to execute the POST request.
Up until this point, our interactions revolved mainly around GET requests, primarily focused on fetching data. Employing React Query, we utilized the useQuery
hook to efficiently manage these operations. However, creating an order involves a POST request that modifies the database. To facilitate this, React Query provides useMutation
, a hook tailored specifically for handling mutation actions like creating, updating, or deleting server data.
The useMutation
hook operates by accepting a mutation function as its parameter, encapsulating the necessary logic for altering data on the server side.
Given our scenario of creating an order based on form inputs, we will pass in the ordersApi.create
method into the useMutation
hook. Let's include the following lines within the file src/hooks/reactQuery/useCheckoutApis.js
.
Next, we'll incorporate the submit button and its corresponding event handler into the Checkout
component. The submit button will include a type
prop set to submit
, ensuring it triggers the necessary action when clicked. The submission logic is designed to generate an order using the mutate
function, which has been aliased as createOrder
, from the earlier established useCreateOrder
hook.
Additionally, we'll introduce a state named isSubmitDisabled
, which evaluates to true
when the form is in the process of being submitted. This state assists in disabling the submit button during the submission process.
Furthermore, we will introduce a redirectToHome
function designed to redirect the user to the product listing page and clear the cart 1500 milliseconds after a successful submission. We will also enhance the handleRedirect
logic to clear the cart and cancel the timeout in case the back button is pressed shortly after submission, but prior to redirection to the product listing page.
First, let's add a function to the cart items store to clear the cart.
Now, update the Checkout
component as follows:
We've implemented the submission logic to manage actions when users click the submit button. However, merely executing the submission isn't enough. How do we ensure users know that their order went through successfully? To achieve this, we will integrate Toastr
from neetoUI, which presents Toast messages in small popups to give users visual cues about their actions.
Here's how the workflow for displaying these Toast messages will function:
- Upon successful placement of an order, the backend will send a translation key labeled as
notice_code
within the response.data object
.
- After converting the keys to camelCase, within the response interceptor,
Toastr.success
will automatically extract this notice code from the provided object and display it as a popup message. To make this work seamlessly, we'll need a translation key in en.json
that matches the one sent from the backend.
- In the event of an error,
Toastr.error
will handle displaying the error as a toast message to alert the user.
Let's incorporate this logic within the response interceptor located in the axios.js
file.
Finally, we'll include all the necessary translation keys in the en.json
file.
Form handling with Formik comes to a close here. In the next lesson, we'll add a section within the Checkout
component to showcase cart items and their total price.
Let's commit the new changes:
You can verify the changes here.