...

/

Lifting up the State

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.

Press + to interact
<!-- 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.

Press + to interact
<!-- 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.

Press + to interact
// router/index.js
import { 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 ...