Code Readability
Ref
Refs are fantastic, but their .value
can give us much to discuss. I like to simplify this debate by keeping the following in mind:
- How can we distinguish between a mutation and just reading a value?
- How can we eliminate the possibility of introducing unintended side effects?
- How can we improve the code to read like natural language?
Example
const optionA = ref('vue')
const optionB = ref('nuxt')
// I can work with this
const choice = optionA.value
// but this is painful!
choice.value = optionB.value
// cluttered code logic with no semantic value
const msg = computed(() => `${optionA.value} & ${optionB.value} rock but ${choice.value} is best!`)
Insight
What if we save the ref.value
syntax only to the left side of =
. This order makes it explicit that we are mutating a reactive value.
For the right side of the =
, we can use the helper functions toValue()
or unref()
. They both communicate that we are reading a reactive value and protect us from introducing side effects.
I favor toValue()
over unref()
because it improves the code's declarative language. Unref is more tied to the framework's implementation details.
Declarative language tells us what something does, while imperative language focuses on how something is done. Connecting the dots with declarative language while going over code is more effortless.
const optionA = ref('vue')
const optionB = ref('nuxt')
// this tells me it wont be reactive anymore
const choice = toValue(optionA)
// this signals we are getting a value from a reactive property
choice.value = toValue(optionB)
// strong visual cues, less cognitive load, no side-effects
const msg = computed(() => `${toValue(optionA)} & ${toValue(optionB)} rock but ${toValue(choice)} is best!`)
This simple convention gives everyone else and me clear visual boundaries of what is going on with a ref
and its effects, decreasing the mental effort of reading the code.