Choose the right tool to define variables in Vue and React
Published 19 days ago
In Vue and React, it's super important to choose the right tool to define variables in components and composables/hooks.
The right tool will highlight key characteristics of the variable.
(React only) Is the variable referenced in a useEffect
callback that should not re-run when the variable changes?
(I call these variables "sneaky", since their main purpose is to sneak around useEffect
constraints in the right situations.)
In Vue, for example, the shallowRef
tool tells us:
- The variable can be any type
- The variable is shallowly reactive (deep mutations won't trigger updates, and must be avoided to keep the system predictable)
- The variable is mutable
- The variable is not derived
In React, if we define something with useCallback
with other variables in its dependency array, that tells us:
- The variable is a function
- The variable is reactive
- The variable is immutable
- The variable is derived
- The variable is not sneaky
When you're reading component code and trying to predict behavior, this is crucial information, and the right tool will communicate all of it.
In Vue, here are our tool choices:
ref
reactive
readonly
computed
shallowRef
shallowReactive
shallowReadonly
customRef
- Nothing (i.e. just use
const
,let
, orfunction
, with plain assignment)
And in React:
useState
useMemo
useCallback
useRef
- Nothing (i.e. just use
const
,let
, orfunction
, with plain assignment)
As you work with these tools, you'll get an intuition for which tool is best in any situation. But the logic behind this intuition is pretty extensive.
To help people learn this, I wrote down all the deciding factors I could think of for both Vue and React, and made a quiz to tell exactly which tool is best.
Quiz
One more thought for Vue developers
In the Vue community, we got a little obsessed with the question of ref
vs. reactive
. I hate to rain on the parade, but that's the least important question to ask when defining a variable.
Hopefully this blog post is a good explanation of why we should move away from that question, and what we should focus on instead. Vue has tons of excellent tools for defining variables—take advantage of them, and enjoy!
One more thought for React developers
The new React Compiler promises to automatically choose useMemo
and useCallback
whenever there's an opportunity to optimize re-render performance. We can simply define variables in plain JavaScript, and the compiler will purportedly choose the right tool for us.
But the official React Compiler docs make zero mention of useEffect
or what impact the compiler might have on our effect timing.
IMHO, effect timing is the hardest part of web dev, and if the React Compiler doesn't automate those decisions, then we still need to be knowledgeable and careful about which tool we use to define variables.
A final thought about multi-step forms
This quiz was also a really good excuse to mess around with an idea I had for implementing multi-step forms with multiple conditional branches:
- Model the form as a list of nodes and edges, as if it were a network (because it actually is)
- Generate the form from the data model
- Collect form state in a single object
- To move forward through the form, use form state to traverse the network data model, computing which "node" should be active
- To move backward through the form, erase the most recent answer, and re-compute the active node based on the new form state
This approach felt pretty awesome! I'm polishing the idea a bit more, and then I'll write a blog post with code examples to explore advantages and disadvantages.