Lifting up the State
Learn how to lift up the state.
We'll cover the following...
Imagine we’re working on a business card editor. We need to create a form that will allow users to upload their pictures and information such as their name, description, phone number, and address.
Implementation
Let’s start by creating two files in a newly scaffolded project. The BusinessCardEditor
component imports and renders the BusinessCardForm
component.
<!-- views/businessCardEditor/BusinessCardEditor.vue --><template><div class="p-8 container mx-auto grid grid-cols-2 gap-8"><BusinessCardForm /></div></template><script>import BusinessCardForm from "./components/BusinessCardForm";export default {components: {BusinessCardForm,},};</script>
It’s good practice to keep the state close to where it belongs, so it does make sense to put it in the form
component.
<!-- views/businessCardEditor/components/BusinessCardForm.vue --><template><div class="shadow-md p-8"><h2 class="text-2xl font-semibold mb-4">Business Card Form</h2><form><div :class="$style.formBlock"><label :class="$style.formLabel">Avatar</label><input type="file" @change="onFileUpload" /></div><div :class="$style.formBlock"><label :class="$style.formLabel">Name</label><input :class="$style.formInput" type="text" v-model="name" /></div><div :class="$style.formBlock"><label :class="$style.formLabel">Description</label><input :class="$style.formInput" type="text" v-model="description" /></div><div :class="$style.formBlock"><label :class="$style.formLabel">Phone number</label><input :class="$style.formInput" type="text" v-model="phoneNumber" /></div><div :class="$style.formBlock"><label :class="$style.formLabel">Address</label><input :class="$style.formInput" type="text" v-model="address" /></div></form></div></template><script>export default {data() {return {avatarFile: null,name: "",phoneNumber: "",description: "",address: "",};},methods: {onFileUpload(e) {this.avatarFile = e.target.files ? .[0];},},};</script><style module>.formBlock {@apply flex flex-col mb-6;}.formLabel {@apply mb-3 font-semibold;}.formInput {@apply border border-gray-50 shadow p-4;}</style>
Let’s also update the routes
config so we can access it.
// router/index.jsimport { createRouter, createWebHistory } from "vue-router";import Home from "@/views/Home";import BusinessCardEditor from "../views/businessCardEditor/BusinessCardEditor.vue";const routes = [{path: "/",name: "Home",component: Home,},{path: "/business-card-editor",name: "BusinessCardEditor",component: BusinessCardEditor,},];const router = createRouter({history: createWebHistory(process.env.BASE_URL),routes,});export default router;
We now have a working form that’s synchronized with the component state. The functionality is done, but now the client is asking to add a nice preview of this form that looks like a business card (as shown in the business card editor figure). The easiest solution would be to simply add code for the preview in the ...