React Developer’s Guide To Vue 3.0

Jakub Antolak
SoftwareMill Tech Blog
5 min readMar 11, 2021

--

During Frontend Talks at SoftwareMill, we discuss trends, tools, and frameworks in the UI development world. We do that not only to take a step out of our “bubble” but also to see if there is anything on the horizon that could improve our work and our customers’ experiences.

Recently, we had Vue.js in scope. As an alternative to React or Angular, it has gained interest among front-end developers for a variety of reasons:

  • it has a learning curve that doesn’t make you sweat
  • its ecosystem becomes richer and richer in the course of time
  • it’s a framework that provides very powerful tooling including CLI, state management, and routing libraries
  • its newest, third version has been available for quite some time now!

I took a deep dive into Vue.js when preparing for the talk and what struck me as a React developer was how Vue 3.0 is similar to it in many ways.

Photo: Severin Höin, Unsplash

Don’t think about that similarity as a weakness, but rather as a strength. Similar APIs help developers coming from “different worlds” to switch between the environments easily when needed, and this was my case indeed!

If you are a React developer that knows Vue.js a bit, but maybe not the newest version, or if Vue 3.0 is still too intimidating to you, here’s a little guide I’ve prepared.

Composition API

One of the main features of Vue 3.0 is the new Composition API which aims to replace the old Options API, giving us much more flexibility when it comes to sharing the logic between components.

Let’s say we have a component that displays a list of recent blog posts published on SoftwareMill’s website, but we want to keep its logic available in different places. We’ll start very simply:

We have a setup function which is invoked before the component is created. It takes two parameters: props (an object with the component's props, no big difference from React) and the context (this piece of information is something different, though).

The context object consists of three elements:

  • attrs - non-prop component attributes such as html node type or event listeners,
  • slots - an object that you can access the <slot /> content with. <slot /> is an element that tells us: the component’s children will be rendered here in the same way as React’s {children} do in jsx. However, slots are a bit more powerful — you can name them in order to render children in more than one place. If you wanted to do the same thing in React, you’d have to use the render props technique.
  • emit - an option used to emit events to the parent component.

In React’s terms, you could think of the setup function as a wrapper for everything that's before the return statement in a functional component. But when using it, you will not have access to the Options API features such as data, computed or methods.

So how do we handle that?

Codesandbox version here

We can store state values inside the setup, but we need to use Vue's ref helper function to make them reactive. Under the hood, ref uses a Proxy-like mechanism, which makes the state value observable. Then we declare our fetching logic and return the list with the load handler in an object. Everything that's returned by the setup is available inside the <template> tag. (Note: props are available there by default, there's no need to return them).

And here’s what the same component would look like in React:

Doesn't watchEffectlook like the useEffect a bit? This function is used to "apply and automatically re-apply a side effect based on reactive state (...). It runs a function immediately while reactively tracking its dependencies and re-runs it whenever the dependencies are changed" (Vue docs again). The difference is that you don't need to specify the dependency array as the second parameter.

If we wanted to load our blogposts list after the component is mounted, though, we’d have to import one of the lifecycle hooks, like so:

The same rule applies to the computed values. If we wanted to display a list filtered by just one author, we’d write:

Hooks and “hooks”

We need to go deeper. Our logic is still not shareable. In order to make it so, we shall use a mechanism that originated in React.

There is a little bit of confusion, though. The official Vue documentation describes hooks as component’s lifecycle methods. However, with Composition API, we can use hooks similar to those known from React. Taking this step will give us the real ability to share our logic between components.

Codesandbox version here

Now we have a useBlogpostsList hook that we can import to any .vue component and invoke inside the setup method. Achievement unlocked! And this is what it would look like in React:

Portals and Teleports

Let’s make some improvements to see if there is anything more similar. Because yes, there is! There are situations when you want to render your component outside of the current virtual DOM tree. You might want a modal that has CSS position: relative set on its parent, but it's required for it to overlay the whole page or you want to use it across different roots. In React, you can use Portal API to do this.

Vue 3.0 introduces Teleports. The implementation differs, however. While React uses the static method of ReactDOM object, Vue gives you the <teleport> component. Simply add desired root's identifier to the teleport's to attribute. Everything you'll put as teleport's children will be rendered inside the modal root div.

Codesandbox version here

We’ve added a <Modal /> component with the <teleport> inside. It uses modal-root div. We’ve set Modal's visibility using the custom hook useModalState, which — on the other hand — uses another custom hook, known from React, but written from scratch here: useState. See the hooks folder in Codesandbox to check it.

Our Modal has the emits option to describe its closing behavior. We simply declare the close event in the emits array and then use the emit context function in the setup to emit it. Thanks to that, the parent component knows what to do.

Fragments

Last but not least, the Fragments. Until recently, it was impossible to put multiple nodes in React component’s render method or as an output of functional components. It was prohibited. In version 16.2.0 Fragments were introduced. Wrapping the markup with <React.Fragment></React.Fragment> or simply <></> dismissed the error, making the component renderable (however, all nodes wrapped inside <></> were still treated as one child by React.Children).

In Vue 2.0, we had the same problem. Leaving the <template> tag with multiple children was causing a red highlight in the IDE. Vue 3.0 supports multiple child nodes so you don't need to worry about additional headings or paragraphs in the template.

Summary

Vue 3.0 makes it easier to make component’s logic available in different parts of your app. It’s a great improvement both from the developer and the client perspective. And while it might be tricky and time-consuming for programmers to swiftly switch between the frameworks and technologies, Vue 3.0 addresses that issue very well, especially for React developers!

As I wrote at the beginning — it’s always good to take a step outside of the “bubble” and see what the world has to offer. Maybe it will be something very useful and give us some fun by the way?

Thanks to Tomasz Krawczyk, Adam Warski & Kaja Polachowska for a review & spellcheck.

--

--