DEV Community

Cover image for To .value or not to .value. That is the vuestion.
c5n8
c5n8

Posted on • Edited on

3 1

To .value or not to .value. That is the vuestion.

Vue 3 with composition api introduces some new ways to create reactive or observable value. There are reactive, ref, and computed. They have quirk in terms of their syntax. Let's use hot food to show it.

Reactive Object

import { reactive, computed } from 'vue'

const coolTemperature = 22

export function useHotFood({ temperatureInCelcius }) {  
  const state = reactive({
    temperatureInCelcius,
    isHot: computed(
      () => state.temperatureInCelcius > coolTemperature
    ),
  })

  function blow() {
    state.temperatureInCelcius -= 10
  }

  // ...

  return {
    state,
    blow,
  }
}
Enter fullscreen mode Exit fullscreen mode

State would lost reactivity if destructured, so it have to be returned as is.

// Using reactive object named state
const hotFood = useHotFood({ temperatureInCelcius: 100 })
hotfood.state.temperatureInCelcius
hotfood.state.isHot
hotfood.blow()
Enter fullscreen mode Exit fullscreen mode

Ref/Computed Object

import { ref, computed } from 'vue'

const coolTemperature = 22

export function useHotFood(args) {  
  const temperatureInCelcius = ref(args.temperatureInCelcius)
  const isHot = computed(
    () => temperatureInCelcius.value > coolTemperature
  )

  function blow() {
    temperatureInCelcius.value -= 10
  }

  // ...

  return {
    temperatureInCelcius,
    isHot,
    blow,
  }
}
Enter fullscreen mode Exit fullscreen mode

Ref value have to be accessed through its value property. Ref may be unwrapped in template, but it causes syntax inconsistency, between template and script block.

// Using ref for each prop of state
const hotFood = useHotFood({ temperatureInCelcius: 100 })
hotFood.temperatureInCelcius.value
hotFood.isHot.value
hotFood.blow()
// or
const {
  temperatureInCelcius, isHot, blow
} = useHotFood({ temperatureInCelcius: 100 })
temperatureInCelcius.value
isHot.value
blow()
Enter fullscreen mode Exit fullscreen mode

This overhead of remembering whether to use .value or not, makes people confused. But it doesn't have to.

Enter vue-extend-reactive

To achieve terser syntax, one way is to extend reactive object, maybe with another reactive object (like getters), or methods.

Reactive object can contain methods when using javascript, but make it more verbose to call it in same block, and create error when using typescript.

And thats why vue-extend-reactive is created,to enable reactive object extension leveraging Proxy object.

Extend reactive object returned from composition function with additional reactive object(such as getters), or additional methods to get these benefits:

  • Simplify api of object returned by a composition function.
  • Eliminate overhead thinking of whether to use or not to use value property of ref or computed object to get its value.

Installation

  • Using NPM
npm install vue-extend-reactive
Enter fullscreen mode Exit fullscreen mode
  • Using Yarn
yarn add vue-extend-reactive
Enter fullscreen mode Exit fullscreen mode

Usage

import { reactive, computed } from 'vue'
import { extend } from 'vue-extend-reactive'

const coolTemperature = 22

export function useHotFood({ temperatureInCelcius }) {  
  const state = reactive({
    temperatureInCelcius,
    isHot: computed(
      () => state.temperatureInCelcius > coolTemperature
    ),
  })

  function blow() {
    state.temperatureInCelcius -= 10
  }

  // ...  

  return extend(state, { blow })
}
Enter fullscreen mode Exit fullscreen mode

Below is the end result after returning extended reactive object.

const hotFood = useHotFood({ temperatureInCelcius: 100 })
hotFood.temperatureInCelcius
hotFood.isHot
hotFood.blow()
Enter fullscreen mode Exit fullscreen mode

This helper is compatible with both Vue 2 (using @vue/composition-api) and Vue 3.

There is one caveat that returned reactive object cannot be destructured as it will lost reactivity, but that is a sacrifice I am willing to make, to get terser and more consistent syntax.

Lastly, I hope this is the way vue package authors create their composition functions or hooks.

Links:

Hostinger image

Get n8n VPS hosting 3x cheaper than a cloud solution

Get fast, easy, secure n8n VPS hosting from $4.99/mo at Hostinger. Automate any workflow using a pre-installed n8n application and no-code customization.

Start now

Top comments (0)

Qodo Takeover

Introducing Qodo Gen 1.0: Transform Your Workflow with Agentic AI

Rather than just generating snippets, our agents understand your entire project context, can make decisions, use tools, and carry out tasks autonomously.

Read full post

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay