TLDR: It is easier to make things great in Vue because it helps you and requires less magic and complexity.
I’ve been playing with the latest version of Nuxt over the last few weekends.
I’ve been using a recent Next (v13) site as the base for a project. I have the basic top level routes recreated now.
So I have touched all the major parts. These are my thoughts on the reasons I think Vue is better than React for content driven sites.
For Vue
- Incredible stability with Vue 3 (released Sep 18, 2020, still the working version) and no plans to break things
- Reactivity system makes DOM updates rather than full renders. So toggling classes is exactly that, instead of re-rendering the entire component. This is called a patch flag
- You can be sure that code you expect to run once only runs once without special attention
Provide
&Inject
work in SSR with less caveats thanContext
&Providers
in React because those are considered "client only"- Automatic fallthrough of attributes (and no
cleanProps
required) - Less hydration mismatch errors because of
v-show
(keep all the DOM you need, just hide it) - The
KeepAlive
component allows you to keep state localized instead of moving it up the tree - Using a named
slot
is much easier than using children in props or making render props - Easier conditions with
v-if
,v-else
, andv-show
- Control flashing/shifting content with
v-cloak
- List rendering is much nicer with
v-for
(plus it can go directly on a Component instead of needing a wrapper) - No
useCallback
oruseMemo
jargon, instead there isv-once
andv-memo
(or evenKeepAlive
) - No need for
Fragment
because multiple root elements are allowed - No need for
Suspense
but it exists in case you want to handle loading in your template instead of your dynamic component loader - Built in
Transition
component for animations - You don't need to alias any of the HTML attributes (ex:
class
vs.className
)
For Nuxt
- Nuxt has hooks for build, runtime, and the server. This makes building plugins/modules much more capable and powerful
- The deployment targets for Nuxt are more democratic and you don't loose features choosing one over another (like with Next ISR)
- The testing story is much more complete in Nuxt with choices for runtime environment (jsdom, happy-dom), and test runner (vitest, jest). There are also built-in mocks and utilities/helpers
- Convenient
ClientOnly
component (that supports a server fallback) - The Nuxt devtools are phenomenal
- Dynamic imports are handled by just prefixing your component with
Lazy
- Working with TypeScript can be odd. There are some weird quirks using it. Most are well documented and can be solved with nice
plop
files or linting - The way to generate the routes in Nuxt that need to be pre-rendered is a bit wonky. You need to make a module and it is not defined in the page level
- Nuxt auto imports are cool but the editor integrations often need to be restarted in order to pick up the changes
- Nuxt auto imports can also be tricky because Types need to be imported but not modules
- Nuxt 3rd party components always need to be imported unless added to auto imports
Conventions in React don’t translate fully to Vue in that large blocks of JS before your template are usually not required. The templating in Vue is much more expressive so you don’t need that huge JS block.
You have no "returns" in Vue, so you end up moving that logic to the template. You can use "if-else" to choose which component to render, or using the built in Component
tag, to select one dynamically. This can be really nice when you have a component that you want to set as a specific element based on it’s props. Think the Button
component that can be an a tag (a
, input[type=submit]
) or a literal type=button
.
Classes are much easier to handle in Vue, so you don’t need the big setup in the front that massages all the classes. You can do this, but it generally isn’t needed. Basically, clsx is built-in.
With better conditionals, your templates are immediately more understandable at a glance. It is clear in the first prop on your component if it will render or not.
The slot
concept is just so much nicer than props.children
and render props.
Using v-show
can help reduce hydration errors since you are still rendering the elements in the output, when the client calls kick in, then the client code takes over. This can be done in React, but you would have to make it a client component as well as use a className
to toggle the visibility like v-show
would.
There was never really a reason to even thing about doing any memoization. It just didn't come up. Because of the way Vue renders, you don't have to optimize for a render loop in the same way you do in React.
It may look on the surface like Vue has a smaller ecosytem, but I think that is partially because Vue has things inclueded that you don't need a dependency for. There is no need for clsx
or an animation tool, because class
and transition
are capable features that are already included.