The Swiss Army knife of every Vue.js developer

Juan Andrés Núñez

Frontend Engineer

Content creator at

?

Composables

The Composable Pattern will help you build (more) Extensible, Adaptable, Controllable and Trustful Vue.js applications.

The Promise

A function that leverages Vue's Composition API to encapsulate and reuse stateful logic.

What

  1. Composition API
  2. Stateful logic (state)
  3. Reactivity

What

import { ref } from "vue"

// We always export a main function
export function useAlert() {
   
  // Stateless: every instance holds its own state
  const isVisible = ref(true)
  
  // We craft our custom logic
  const toggleVisibility = () => isVisible.value = !isVisible.value 
  
  // We expose what we want to consume
  return {
    isVisible,
    toggleVisibility
  }
}

What

  • Convention is start with Use...
  • Not the same as mixins
  • You don't even need Vue 3

When

When

  • State stores
  • Controllers
  • Reactive UI utils
  • Any other creative use

Where

  • Everywhere...
  • Not only a UI concept
  • Are omnipresent
  • Local to a feature
  • Global to a system

Why

The Composable Pattern will help you build (more) Extensible, Adaptable, Controllable and Trustful Vue.js applications.

Extensible: start small, grow with the project

  • Stateless or stateful
import { ref } from "vue"

export function useAlert() {

  // Stateless
  const isVisible = ref(true)
  ...
}
import { ref } from "vue"

// Stateful
const isVisible = ref(true)

export function useAlert() {
  ...
}

Extensible: start small, grow with the project

  • Options pattern
import { ref } from "vue"

const isVisible = ref(true)

// We expect an options object 
export function useAlert(options) {
  // We specify a default
  const { isDanger = true, awaitResult = true } = options
  ...
}

Extensible: start small, grow with the project

  • Composition
import { ref } from "vue"
import { useLocalStorage }  from '@/composables'

const isVisible = ref(true)

export function useAlert() {
  const { save, check, remove } = useLocalStorage({ key: 'my-app'})
  ...
}

Adaptable: fit in every app layer, work in every env.

  • Domain / business logic
UseEvent
UseCalendar
UsePayment
  • Native API's
UseDarkMode
UseIntersectionObserver
  • Data modeling
UseFilter
UseUnique
UseReduce

Controllable: decide what to expose

  • Explicit return
export function useAlert() {
  const isVisible = ref(true)
  const toggleVisibility = () => isVisible.value = !isVisible.value 
  
  return {
    toggleVisibility
  }
}
  • Readonly properties
import { ref, readonly } from "vue"

export function useAlert() {
  const isVisible = ref(true)
  const toggleVisibility = () => isVisible.value = !isVisible.value 
  
  return {
    isVisible: readonly(isVisible),
    toggleVisibility
  }
}

Controllable: decide what to expose

  • Easy aliasing
import { useAlert } from '@/composables'

const { isVisible: isNotHidden, toggleVisibility } = useAlert()
export function useAlert() {
  ...
  
  return {
    isNotHidden:isVisible,
    toggleVisibility
  }
}

Controllable: decide what to expose

Trustful: easier to test, easier to maintain

import { useAlert } from '.'

describe('useAlert', () => {
    it('has the initial state as visible', () => {
        const { isVisible } = useAlert()

        expect(isVisible.value).toBe(true)
    })

    it('toggleVisibility() mutates the state', () => {
        const { isVisible, toggleVisibility } = useAlert()
        
        toggleVisibility()

        expect(isVisible.value).toBe(false)
    })
})

How

How

  • VueUse
  • Build your own collection

Thank you 🙏

(See you in the workshop 🔥)

The Swiss Army knife of very Vue.js developer

By Juan Andrés Núñez

The Swiss Army knife of very Vue.js developer

  • 21