Why Components?
Components are the building blocks of modern front-end development. They allow us to break down complex UIs into smaller, reusable, and self-contained pieces of code. This not only improves code readability but also enhances maintainability, scalability, and testability.
Vue Formik provides a set of components that encapsulate common form patterns, such as input, textarea, and many more. These components are designed to work seamlessly with Formik and help you build forms faster and more efficiently. Let's see how components can simplify form development by comparing two approaches: one without components and the other with components.
Without Components
<template>
<form @submit="formik.handleSubmit">
<label for="name">
Name
<input
id="name"
name="name"
:value="formik.values.name"
@input="formik.handleFieldChange"
@blur="formik.handleFieldBlur"
/>
<p v-if="formik.hasFieldError('name')">
{{ formik.getFieldError('name') }}
</p>
</label>
</form>
</template>
<script setup lang="ts">
import { useFormik } from "vue-formik";
const formik = useFormik({
initialValues: {
name: "",
},
onSubmit: (values) => {
console.log(values);
},
});
</script>
In this example, the code involves directly handling the value, input event, blur event, and field error messages for each input field. While this approach works for simple forms, it becomes cumbersome and error-prone as the form grows in complexity. Each field requires repetitive boilerplate code, making the implementation harder to read, debug, and maintain.
With Components
<template>
<FormikForm :formik="formik">
<FormInput name="name" label="Name" :formik="formik" />
</FormikForm>
</template>
<script setup lang="ts">
import { useFormik, FormInput, FormikForm } from "vue-formik";
const formik = useFormik({
initialValues: {
name: "",
},
onSubmit: (values) => {
console.log(values);
},
});
</script>
By using a FormInput
component, we encapsulate all the repetitive logic into a single reusable unit. This significantly reduces the amount of code in our form and ensures consistency across input fields. We only need to pass the necessary name
and formik
props, and the component takes care of managing events, validations, and error handling for us.
Benefits of context (provide/inject)
Did you notice that we've to pass formik
prop to each input field? This is where the power of Vue's provide/inject comes into play and component based approach shines. We can provide the formik context at the top level of our form.
Every exported component implements a formik context that is configured to take an injection of formik instance. This way, we can inject the formik instance into the component tree and access it from any child component without having to pass it down as a prop.
<template>
<FormikForm>
<FormInput name="name" label="Name" />
</FormikForm>
</template>
<script setup lang="ts">
import { provide, ref } from "vue";
import { useFormik, FormInput, FormikForm } from "vue-formik";
const formik = useFormik({
initialValues: {
name: "",
},
onSubmit: (values) => {
console.log(values);
},
});
provide("formik", formik);
</script>
Comparison: Without vs. With Components
Using components brings a clear advantage in terms of readability, reusability, and ease of maintenance. Without components, you might struggle with verbose and repetitive code that is challenging to manage as your application grows. In contrast, with components, the codebase remains clean and modular. Updates to shared logic, such as validation rules, can be applied in one place rather than across multiple input fields.
We will explore more about the power of components in the next section.