Vue.js - A Cleaner and More Effective Approach to Frontend Development
The days of jQuery are long gone. Folks are no longer littering their code bases with JavaScript snippets to introduce interactivity.
The days of jQuery are long gone. Folks are no longer littering their codebases with JavaScript snippets to introduce interactivity. Although jQuery made developing rich-interactive websites super easy, the long-term maintenance costs quickly get out of hand for sizable applications.
Enter three popular front-end frameworks that try to alleviate the drawbacks of coding in jQuery:
- React: Built by Facebook to help better manage stateful applications, starting with the newsfeed and Instagram - makes heavy use of JSX for templating.
- Angular: Built by Google to help solve "Google-scale" problems - an opinionated framework with all the bells and whistles built directly into the framework. Angular is a comprehensive and well-polished framework; unfortunately, the learning curve is the highest of the bunch. Angular is heavily steeped in theoretical concepts - with high reliance on RxJS.
- Vue: Evan Vue wanted to build a lighter Angular after working with it at Google. The result is a hybrid of Angular and React with the best of both worlds. Vue borrows some of the better aspects from Angular while giving developers a more pleasant experience.
In this article, I will explore why someone might want to choose Vue.js over some of the other options available out there.
Component-based architecture
When developing web applications using component-based architecture, you are faced with the following decisions:
- How should your component code be organized?
2. How do you ensure your imported CSS files don't conflict with other elements in the app? 3. How should you go about managing state?
Take a look at the following example of a typical React functional component, using redux for managing state with the convenience connect() function:
store.js
import { createStore, combineReducers } from "redux";
export const DELETE_MESSAGE = "DELETE_MESSAGE";
export const deleteMessage = (id) = ({
type: DELETE_MESSAGE,
messageId: id
messages.js
});
const initialState = [];
const messagesReducer = (state = initialState, action) => {
switch (action) {
case DELETE_MESSAGE:
return state.filter(m => m.id != action.id);
// other state updates
default:
return state;
}
};
const userReducer = ...
const reducer = combineReducers({
messages: messagesReducer
user: userReducer
...
});
export const store = createStore(reducer);
messages.js
import React from "react";
import { createStore, connect } from "redux";
import "messages.scss";
export const Messages = ({messages, user, deleteMessage}) => ({
<div className="messages">
{# Looping with conditional rendering #}
{
messages.length?
message.map((message) => (
<div className="message">
{ message }
{ user.isAdmin &&
<span onClick={deleteMessage(message.id)}>X</span>
}
</div>
))
:
<div>No messages</div>
}
</div>
});
export default connect(
state => ({
messages: state: messages,
user: state.user
}),
dispatch => ({
deleteMessage: id => dispatch(deleteMessage(id))
})
)(Messages);
React makes heavy use JSX for outputting HTML. In my opinion, JSX seems like a hack and afterthought. Although having JavaScript at your disposal has its perks, this code is just plain messy. Every time I have to work with JSX, I spend unnecessary brain cycles trying to figure out how to format it to look right. The end result never looks quite right.
Aside from JSX, most folks using React opt to use Redux for managing state. Redux is a great way to solve the state management problem, but it requires a lot of boilerplate and code duplication just to get started:
- Action Types - basic string constants.
- Action Creators - functions that return actions.
- Reducers - functions that update the global app state based on actions that are dispatched in different areas of code.
What this means, is that for every new state change that needs to be added to the app, the developer has to modify code in at least three locations. Knowing this, the authors of Redux have come up with solutions to help minimize the boilerplate with tools such as The Redux Toolkit.
The same component using Vue's single file components and Vuex for state management:
store.js (with Vuex)
import Vuex from 'vuex';
import Vue from 'vue';
Vue.use(Vuex);
export const store = new Vuex.Store({
state: {
user: null,
messages: []
},
mutations: {
deleteMessage (id) {
state.messages = state.messages.filter(m => m.id !== id);
},
setMessages (messages) {
state.messages = messages;
},
...
},
getters: {
warningMessages () {
return state.messages.filter(m => m.type === 'warning');
}
},
actions: {
deleteMessage({commit}, messageId) {
commit('deleteMessage', messageId);
},
refreshMessages({commit}) {
fetch('/messages.json')
.then((response) => response.json())
.then((data) => commit('setMessages', data.messages))
.catch((err) => console.error(err));
},
...
}
});
messages.vue (with Vuex)
<template>
<div class="messages" v-if="messages.length">
<div className="message" v-for="message in messages">
{{ message }}
<span @click="deleteMessage(message.id)" v-if="user.isAdmin">X</span>
</div>
</div>
<div v-else>
No Messages
</div>
</template>
<script>
import { store } from "../store";
module.exports = {
computed: {
user: () => store.state.user,
messages: () => store.state.messages,
},
methods: {
deleteMessage(id) {
store.dispatch('deleteMessage', id)
}
}
};
</script>
<style lang="scss" scoped>
.message {
font-size: 2em;
text-align: center;
color: #eee;
}
</style>
Strengths of Vue.js
Clean Templates
MVC purists will be delighted to see no JavaScript code in the view layer. Single file components, as shown here, package everything related to a component in a single encapsulated file: template code, JavaScript and (scoped) CSS. If you happen to be one of those weird die-hard JSX fans, there are methods for using it in Vue as well.
Scoped CSS
Scoped CSS allows you to style only the HTML elements in your components and nothing else - allowing for consistent behavior and simpler namespacing of your CSS selectors - without the need for multiple levels of CSS selectors.
Cleaner State Management
Although the battle between Redux and Vuex is a toss-up. Vuex seems to provide a more polished approach that can create a more welcoming environment to newbies and gurus alike. Some of the benefits of sticking with Vuex include:
- Less boilerplate - assuming you go with the vanilla version of the store setup.
- A cleaner method for handling of async operations without the need for thunks or the like.
- Getter methods - a single location for app-wide state helper accessors.
- Simpler and straightforward integration with components, without the need to pull in additional libraries to get going. This is due to the fact that Vuex was designed to be used with Vue from the get- go.
Conclusion
At the end of the day, both React and Vue.js provide us with great tools to help build advanced web applications ready for the coming years. Upper management might like to hear that Vue.js has the easiest learning curve - allowing a developer to get up to speed in a matter of days. Developers will also feel at home with an environment where they don't need to wrestle with the framework to knock out the next feature.
Happy Coding! :)
About the Author
Ramin Rakhamimov joined the team at JBS in October, 2019. You can view his blog/portfolio at https://raminrakhamimov.com/
The JBS Quick Launch Lab
Free Qualified Assessment
Quantify what it will take to implement your next big idea!
Our assessment session will deliver tangible timelines, costs, high-level requirements, and recommend architectures that will work best. Let JBS prove to you and your team why over 24 years of experience matters.