Component Framework Concepts in Vue vs React
Component frameworks are tools for building applications such that the UI and logic are segmented into separate reusable components. Today’s component frameworks include React, Vue, Angular, Ember, Svelte, etc.
Vue and React make use of common framework concepts such as handling states, props, refs, lifecycle hooks, events, etc. These two frameworks are widely used in web development today. They use nearly similar patterns for building UI in the form of reusable components, but in this blog post you will learn about component framework concepts and how they are done in Vue compared to how they are done in React.
Installation and Setup
Let’s start by comparing the installation process of both frameworks.
Vue
To install Vue CLI (command line interface), the following command is used:
npm install -g @vue/cli
To check the version, run the following command in your terminal.
vue --version
To create a new project, run the following command.
vue create project_name
cd project_name
npm run serve
React
To install React, run the following command on your terminal:
npm install -g create-react-app
To create a new project, run the following command.
npx create-react-app project_name
cd project_name
npm run start
Props
Component frameworks use props to pass data from parent to child components, a crucial technique for both.
Vue
In Vue, props are passed as strings using quotations or variables using the v-bind
directive, which can also be written as just a :
character.
Passing props to child component
// passing props from to Modal component
<template>
<Modal :isOpen="pageLoaded" title="Survey Form" />
</template>
Accessing props in child component
// Modal Component
<template>
<form v-if="isOpen">
<p>{{ title }} </p>
<!-- ...other form elements -->
</form>
</template>
<script setup>
const props = defineProps({
isOpen: Boolean,
title: String
});
</script>
React
In React, props are passed as strings also using quotes or as variables using curly braces like so:
Passing props
<div>
<Modal isOpen={pageLoaded} title="Survey Form" />
</div>
Accessing props
function Modal({isOpen, title}) {
return (
{isOpen &&
<form>
<p>{ title }</p>
// ...other form elements
</form>
);
}
Events
Components can listen to specific events such as mouse events (e.g., click, mouseover, etc.) and keyboard events (e.g., keydown, keyup, etc.) Event handling is also a necessity in both frameworks.
Vue
In Vue, events are created using the v-on
directive, which can also be written as @
like so
<template>
<button @click="displayName"> Show Name </button>
<template>
<script setup>
function displayName() {
alert('Lawrence Franklin');
}
</script>
React
In React, events are created using the typical JavaScript inline event methods such as onClick, onKeyDown, onKeyUp, etc.
function NameAlert() {
const displayName = () => {
alert('Lawrence Franklin');
}
return (
<button onClick="displayName"> Show Name </button>
);
}
State
Component frameworks use states to manage reactivity within components. States are updated in real-time across components. Handling the global state across a website is a critical issue.
Vue
In Vue, states can be created using the ref()
or reactive()
method, which does the same thing except ref are accessed using the .value
property while reactive are used directly (they’re already unwrapped). These methods help to creative reactivity within components.
<template>
<div>
<p>{{ firstname }}</p>
<p>{{ lastname }}</p>
</div>
</template>
<script setup>
import { ref, reactive } from 'vue';
const firstname = ref('Franklin');
console.log(firstname.value);
const lastname = reactive('Lawrence');
console.log(lastname);
</script>
Reactive values can be watched using watch()
and watchEffect()
methods. These methods tracks changes in reactive values and runs a callback function every time those value changes. The only difference between these methods is that watchEffect()
runs once initially and then starts watching for changes.
import { watch, watchEffect } from 'vue';
// watch
watch( firstname, () => alert('firstname changed!');
// watchEffect
watchEffect(lastname, () => alert('lastname changed');
React
React uses the useState()
hook to track state changes in a component and create side effects.
import { useState } from 'react';
function ShowName() {
const [firstName, setFirstName] = useState('Franklin');
const [lastName, setLastName] = useState('Lawrence');
console.log(firstName, lastName);
return (
<div>
<p>{ firstname }</p>
<p>{ lastname }</p>
</div>
)
}
To listen for state changes, React uses the useEffect()
hook. This hook accepts a callback function and an array of dependencies, and it fires the callback function whenever the values of those dependencies change. Dependencies could be of any data type. Here’s an example:
import { useEffect } from 'React';
useEffect(() => {
console.log('name updated!');
}, [firstName, lastName]);
Open Source Session Replay
OpenReplay is an open-source, session replay suite that lets you see what users do on your web app, helping you troubleshoot issues faster. OpenReplay is self-hosted for full control over your data.
Start enjoying your debugging experience - start using OpenReplay for free.
Refs
Sometimes you need to work directly with DOM elements for things like adding some animations, setting an input field to focus or blur, etc. To do this, most component frameworks provide you with a reference functionality (Vue and React make use of ref
), which can be used to reference a DOM element.
Vue
In Vue, template ref written with the ref
keyword is used on the DOM element and accessed like so:
<template>
<input type="text" ref="name" />
</template>
<script setup>
import { ref } from 'vue';
const name = ref(null);
handleBtnClick(() => {
name.value.focus();
}
</script>
React
In React, refs are used a bit differently. They reference DOM elements using the ref
keyword and the useRef()
hook, which are then accessed using the .current
property like so:
import { useRef } from 'react';
function MyName() {
const name = useRef(null);
handleBtnClick(() => {
name.current.focus();
});
return (
<input type="text" ref="name" />
<button onClick={handleBtnClick}> Start typing </button>
)
}
Two-way Data Binding
Data can be (and are usually) bound in “two-way”, which means that the data can be updated in two ways. This is used with form input fields such as input
element, select
element, textarea
element, checkbox element
, etc. The input value can be changed via the element and also via code in such a way that they are in sync, i.e., change in one way (e.g., in code) updates the value in the other instance (e.g., in input field).
Vue
Vue uses the v-model
directive to create a two-way binding like so:
<template>
<input v-model="searchQuery" />
</template>
<script setup>
import { ref } from 'vue';
const searchQuery = ref('');
// searchQuery.value can be updated here, and it reflects in the input field instantly
</script>
React
React uses something called controlled inputs to bind data two-way like so:
import { useState } from 'react';
function MyComponent() {
[searchQuery, setSearchQuery] = useState('');
const handleChange = (event) => {
setSearchQuery(event.target.value);
}
return (
<input value={searchQuery} onChange={handleChange}/>
);
}
Dynamic Rendering
Sometimes, components are rendered based on certain conditions. In order words, components can be dynamically rendered depending on the outcome of a specified condition.
Vue
Vue uses the v-if
, v-else
and v-show
directives to render a component dynamically based on a specified condition. The example below illustrates this concept:
<template>
<div>
<p v-if="isLoggedIn"> Welcome </p>
<p v-else> Please Login </p>
<button v-show="!isLoggedIn">Login</button>
</div>
</template>
React
React leverages JavaScript’s conditionals such as if
, &&
, or ternary operator to dynamically render a component. Here’s an example to illustrate this:
function MyComponent() {
return (
{isLoggedIn ?
<p>Welcome</p> :
<p> Please Login </p>
}
{!isLoggedIn && <button> Login </button>}
);
}
Passing Children
Sometimes you want to pass children elements to other components, not just props. Component frameworks like Vue and React provide a means for you to achieve this.
Vue
Vue makes use of slots to pass children elements. Here’s an example of how you can use them:
Modal Component, this is the component that receives children elements
// Modal.vue
<template>
<div>
<h1>Welcome</h1>
<slot><slot>
</div>
</template>
UserPage Component, this is the parent component that passes the children elements
// UserPage.vue
<template>
<div>
<h1>Survey Form</h1>
<Modal>
<p>Kindly fill out this survey...</p>
<input type="text" />
<button>Submit</button>
</Modal>
</div>
</template>
React
React provides you with the children
prop value similar to slots from Vue to pass children elements. Here’s an example:
Modal Component, this is the component that receives children elements
function Modal( {children} ) {
return (
<div>
<h1>Welcome</h1>
{ children }
</div>
);
}
UserPage Component, this is the parent component that passes the children elements
function UserPage() {
return (
<div>
<h1>Survey Form</h1>
<Modal>
<p>Kindly fill out this survey...</p>
<input type="text" />
<button>Submit</button>
</Modal>
</div>
);
}
Conclusion
At this point, you’ve learned most concepts used in component frameworks, such as states, props, components, events, etc. You have also learned how these concepts can be implemented in Vue vs. React. Seeing that these concepts are commonly used across component frameworks, it is relatively easy to transition from one framework to another once you get familiar with how these concepts work.
A TIP FROM THE EDITOR: For another comparison involving React and Vue, check out our Next.js vs NuxtJS: a comparison of two powerhouses article.