Now Available React Programming: The Big Nerd Ranch Guide
Front-End ReactBased on our React Essentials course, this book uses hands-on examples to guide you step by step through building a starter app and a complete,...
Picking up a new framework or library can seem intimidating. The good news is that React and Vue are two popular, well-supported tools for front-end development, and if you already know one, you can leverage your knowledge to become productive with the other relatively quickly.
Both are JavaScript-based, use a virtual DOM, and use composable, reactive components to build applications. They both have CLIs that take care of the boilerplate required to spin up an application quickly and easily. This blog is written with React developers learning Vue in mind, but if you are a Vue developer learning React, stick around. Many of the big, practical differences between the two come down to syntax and knowing one of the two can be easily leveraged into learning the other.
By exploring two applications, one written in React and one written in Vue, that output identical content in the browser, compare how they accomplish the same goal (both were scaffolded with their respective CLIs, Create React App and Vue CLI). Both applications make a request to an API that returns an array of music genres that will be rendered into a list of cards. You can find repositories for the applications below if you want to clone them and experiment, or you can just read along with the code snippets. Both applications are admittedly heavy-handed solutions to the problem presented but should give enough context to understand the basics of both technologies.
The main entry point for both applications is the <App />
component. Comparing the React and Vue <App />
components, it may not be instantly clear that React uses JSX to create component structure, while Vue uses HTML. This will become more apparent as you move along.
What does stand out is that not only does the Vue component import the child components it needs, it also registers them in the exported object in the script tag. If you are a React developer and forget to do this, you will get a big, nasty error. Vue registering components this way allows child components that do not need updating to avoid a re-render.
// App.js import React from "react"; import GenreList from "./GenreList"; import "./App.css"; const App = () => ( <div id="app"> <h1>Genres</h1> <GenreList /> </div> ); export default App;
// App.vue <template> <div id="app"> <h1>Genres</h1> <GenreList /> </div> </template> <script> import GenreList from "@/components/GenreList.vue"; export default { name: "App", components: { GenreList } }; </script> <style> #app { font-family: Avenir, Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-align: center; color: #2c3e50; margin-top: 60px; } </style>
By convention, Vue also provides functionality identical to what something like styled-components provides for React. By adding the scoped
attribute to the style tag in a Vue component, a unique ID is added to the component that limits the styles to that component only. Both CRA and Vue CLI allow simple setup for using SCSS instead of CSS.
<GenreList />
does the heavy lifting of the application, by making your API call, managing the state of the application, and rendering a list of genre cards. Both applications import an identical genreService
function that provides the data for the component. Each application sets the response to their internal state management and then iterates over the array of genre objects to render genre cards.
In the React version, you make the API call inside of a functional component with the useEffect
hook (this could also be accomplished in a class component with the componentDidMount
lifecycle method), and update state with the response data using the useState
hook (in a class component, you would call setState
on a successful response). You can then map
over the genres array in state
and render a <GenreCard />
for each genre.
// GenreList.js const GenreList = () => { const [genres, setGenres] = useState([]); useEffect(() => { genreService .getGenres() .then((response) => { setGenres(response.data); }) .catch((error) => console.log("There was an error", error)); }, []); return ( <div className="genre-list"> {genres.map((genre) => ( <GenreCard genre={genre} key={genre.id} /> ))} </div> ); };
Vue 2 doesn’t have the concept of functional versus class components (although Vue 3 will). In GenreList.vue
, you use the mounted
lifecycle method to make your API call, and you store it in data
, which is analogous to React state
. In your data
description, you give genres
a default value of an empty array so that you don’t have any problems when iterating over genres before the API call resolves.
// GenreList.vue <template> <div class="genre-list"> <GenreCard v-for="genre in genres" :key="genre.id" :genre="genre" /> </div> </template> <script> import GenreCard from "@/components/GenreCard.vue"; import genreService from "@/services/genreService"; export default { components: { GenreCard }, data() { return { genres: [] }; }, mounted() { genreService .getGenres() .then(res => (this.genres = res.data)) .catch(error => console.log("There was an error", error)); } }; </script> <style lang="css" scoped> .genre-list { padding: 0 15%; } </style>
The syntax for iterating over a list in Vue is a bit different than React. Since you are using HTML instead of JSX, you don’t have access to the full power of JavaScript in your template, so Vue uses directives, or special attributes in the markup, that act as instructions to Vue on what to do to the DOM. In this case, you use the v-for
directive to tell <GenreList />
to render a component (or HTML element) for every element in a list. Additionally, you can’t use curly brackets to pass props to child components in Vue, so you will need to use v-bind
directives to pass props to a child component. This can be written as:
<li v-for="item in items" v-bind:key="item.id" v-bind:item="item">
or
<li v-for="item in items" :key="item.id" :item="item">
Both do the same thing, the second is just a shorthand syntax.
The last component to review in this application is <GenreCard />
, which takes a genre object as a prop and renders the data from that object.
In React, <GenreCard />
is a functional component that destructures props on the way in and renders a simple card with a genre and a description.
// GenreCard.js const GenreCard = ({ genre }) => { return ( <div className="genre-card"> <h4>{genre.genre}</h4> <p>{genre.description}</p> </div> ); }; export default GenreCard;
The Vue implementation of <GenreCard />
is similar, although you are required to describe the props the component expects to receive. This is very similar to React’s prop-types
, although it is not optional in Vue. Vue also uses double curly brackets, called “mustaches,” to inject data into a template, as opposed to React’s single set of curly brackets.
// GenreList.vue <template> <div class="genre-card"> <h4>{{ genre.genre }}</h4> <p>{{ genre.description }}</p> </div> </template> <script> export default { props: { genre: Object, }, }; </script> <style lang="css" scoped> .genre-card { padding: 20px; margin-bottom: 20px; border: 2px solid black; } </style>
If you’ve been using React or Vue in your development, hopefully this blog has encouraged you to try something new that you aren’t familiar with. Differences are to be expected, but these two technologies are very similar in terms of philosophy, implementation, speed, and ease of use. Developers shouldn’t be discouraged from moving between the two. In fact, working with both should be encouraged, because it makes developers more versatile and expands the range of projects they can work on.
Based on our React Essentials course, this book uses hands-on examples to guide you step by step through building a starter app and a complete,...
Svelte is a great front-end Javascript framework that offers a unique approach to the complexity of front-end systems. It claims to differentiate itself from...
Large organizations with multiple software development departments may find themselves supporting multiple web frameworks across the organization. This can make it challenging to keep...