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.