Vue Composition API vs React Hooks - the core difference
React Hooks took the web development scene by storm when they were released back in early 2019. They were the reason I gave React a second look, and also why I have loved using it ever since.
Beyond my personal experiences, React Hooks inspired a lot of other developers, articles, tutorials, and even whole UI libraries and frameworks. Among those was Vue and with its Composition API, it showcased its own vision for React Hooks’s “competitor”.
Being a long-time Vue user and React Hooks fan, I simply had to check out Vue 3 and its Composition API. And so I did and loved using it ever since - potentially even more than React Hooks.
With this in mind, after some experimenting, I’ve noticed the single biggest architectural difference between React Hooks and Vue Composition API. A difference that can be the decisive factor when it comes to which API you prefer using.
I casually call this difference “IN vs OUT”, and today would like to explain it to you. Let’s get into it!
View rendering
To understand the “IN vs OUT” difference, or rather the very meaning of it, you have to first understand, how both APIs work, especially within the bigger “rendering context” of both UI frameworks.
React
In React, Hooks can be used in function components. These, on the other hand, work like render()
methods in legacy class-based components. On every re-render, the whole function gets executed, running from top to bottom… except for hooks.
import React, { useState, useEffect } from "react";
const Example = () => {
const [count, setCount] = useState(0);
useEffect(() => {
console.log(`You clicked ${count} times`);
}, [count]);
return (
You clicked {count} times
setCount(count + 1)}>Click me
);
};
React Hooks with some JS magic, “omit” the standard top-to-bottom execution. With useState()
you define state once, and only modify it later when needed - no new state is created on every re-render. The same goes for useEffect()
with which you can run a particular callback (a set of code), not on every re-render, but only on component initialization, general, or specific state property update.
This “magic of hooks”, is what makes React Hooks so good. They allow you do something that wasn’t possible before, in a clean and easy way.
However, it’s not all sunshine and rainbows. Due to their implementation and complexities, React Hooks require you to follow “the rules of hooks”, which apart from an ESLint plugin, aren’t at all assured in runtime JS. There’s also a high risk of unnecessary re-renders and memory leaks if you e.g. forget or misuse the useEffect()
hook.
Vue
Now, in Vue 3, with composition API, components work fairly differently. Your component is an object, with an optional type-safe defineComponent()
wrapper around it. This object then defines the component’s props
, and the whole setup()
method, which is where Composition API steps in.
When compared to React’s function component’s body, Vue’s setup()
runs only once, setting up the component, and returning the proper render function (when not using templates).
The Composition API can be used inside the setup()
method. But again, the fact that setup()
runs only once, is where the Composition API differs from React Hooks the most.
Here, you don’t have to worry about memory leaks or unnecessary re-renders (at least not for the same reasons as in React), but you also have to adjust your mindset to a different kind of workflow. Instead of defining what code shouldn’t be executed upon which re-render, you’ll be deciding what code should be executed upon which state property update.
As for how it could be applied to the previous React example:
import { defineComponent, ref, watch } from "vue";
const Example = defineComponent({
setup() {
const count = ref(0);
const onClick = () => {
count.value = count.value + 1;
};
watch(count, (countValue) => {
console.log(`You clicked ${countValue} times`);
});
return () => (
You clicked {count.value} times
Click me
);
},
});
It might feel a bit weird, as we’re using Vue 3 with JSX here, but that’s just because we can, and also it makes it more comparable with React. It’s also my favorite way to do Vue 3 now (with TypeScript and JSX), and I detailed the whole setup in the previous blog post if you’re interested.
setup() vs React
Now, making such comparisons might feel a bit disingenuous, as React doesn’t have anything directly comparable to Vue’s setup()
. In class-based components, its lifecycle callbacks are defined as separate methods, and in function components, the whole component’s body is a render function.
If anything, maybe we should rather compare React’s function components, with Vue’s functional components to even out the playing field? Then again, Vue’s FCs are stateless, and as of Vue 3, they’re not recommended (because of negligible performance gain).
Thus, there’s no perfect solution to this problem. However, the most rational one would be to compare the current default component creation methods from both platforms, so function components for React and stateful components for Vue.
Going further this way, we could say that it’s best to compare the places where the compared APIs should be used. This means the body of function components in React, and setup()
method in Vue. Again, not an ideal comparison, but arguably one of the best we can make.
IN vs OUT
Now, this technical overview should give you a good idea of the biggest architectural difference between Composition API and React Hooks. However, if it didn’t, then the “IN vs OUT” should make it finally clear.
For me, “IN vs OUT” visualizes well the difference between React Hooks and the Composition API. It’s really simple and works like this:
- Imagine 2 “pools” - one for each framework - both grouping the framework render functions and accompanying code.
- For React you can consider everything to be “in the pool” by default. React Hooks are what allows you to filter “OUT” the unnecessary stuff “from the pool” on each update.
- As for Vue, it works the opposite way. You start with only the render function in the pool and use the Composition API to add new stuff to it on each update.
So, Vue Composition API makes stuff “IN” and React Hooks - “OUT”. Simple to remember, very visual, and creative.
Bottom line
I hope this quick explanation - whether from the technical or visual side, helped you understand the core difference between both APIs better. Who knows, maybe it even made you consider switching to another framework? Let me know of your React Hooks and Vue Composition API experiences, and what do you think of my “IN vs OUT” comparison in the comments below!
As always, for more web development goodness, both creative and technical, follow me on Twitter, Facebook, and through my newsletter. Thanks for reading and happy coding!
If you need
Custom Web App
I can help you get your next project, from idea to reality.