npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

vue-extend-reactive

v1.1.4

Published

Vue helper to extend reactive object

Downloads

35

Readme

Notice

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

Intro

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 object to get its value.

Table of Contents

  1. Installation
  2. Usage
  3. API Reference
  4. Motivation
  5. License

Installation

  • Using NPM
npm install vue-extend-reactive
  • Using Yarn
yarn add vue-extend-reactive

Usage

<template>
  <main>
    <div>
      Hot Food!
    </div>
    <div>
      Temperature: {{ hotFood.temperatureInCelcius }} C
    </div>
    <div>
      Is it cool?: {{ hotFood.isCool ? 'Just cool. Into the mouth!' : 'Nope' }}
    </div>
    <div>
      <button v-if="hotFood.isHot" @click="hotFood.blow()">
        Blow
      </button>
      <button v-else-if="hotFood.isCool" @click="hotFood.heatup()">
        Again
      </button>
    </div>
  </main>
</template>

<script>
// using Vue 2 with composition-api plugin
// import { reactive } from '@vue/composition-api'
// or Vue 3
import { reactive, computed, onMounted, watch } from 'vue'
import { extend } from 'vue-extend-reactive'

export default {
  setup() {
    const hotFood = useHotFood({ temperatureInCelcius: 100 })

    return {
      hotFood,
    }
  }
}

const coolTemperature = 22

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

  function heatup() {
    state.temperatureInCelcius = temperatureInCelcius
    coolingIntervalId = setInterval(
      () => state.temperatureInCelcius -= 1,
      1000,
    )
  }

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

  let coolingIntervalId

  watch(
    () => state.temperatureInCelcius,
    (temperatureInCelcius) => {
      if (temperatureInCelcius <= coolTemperature) {
        clearInterval(coolingIntervalId)
      }
    }
  )

  onMounted(() => {
    heatup()
  })

  return extend(state, {
    heatup,
    blow,
  })
}
</script>

API Reference

export default extend

export declare function extend<O extends Dictionary, E extends Dictionary>(object: O, extension: E): O & E

interface Dictionary {
  [key: string]: any
}

Motivation

Both reactive and ref have quirk in terms of their syntax. Let's use hot food example above to show it.

Return reactive object returned as is

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,
  }
}

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()

Return refs

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,
  }
}

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 vue-extend-reactive

To achieve terser syntax, reactive object needs to be extended, 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, especially in typescript.

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 })
}

Below is the end result after returning extended reactive object.

const hotFood = useHotFood({ temperatureInCelcius: 100 })
hotFood.temperatureInCelcius
hotFood.isHot
hotFood.blow()

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.

License

MIT