Vue composable loses reactivity

Viewed 220

I'm trying to pass reactive data/a ref (limit) into a composable (useItemsShowing()). Whenever I update limit by pressing the button I want the composable to re-run and give me an updated return value.

However, I only get the initial value of the composable. What am I missing?

Reproduction in Vue SFC Playground

Component.vue

<script setup>
import { ref, toRef} from 'vue'
import { useItemsShowing } from './useItemsShowing.ts'
  const limit = ref(10)
  const totalCount = 61
  
  const { itemsShowing, showLoadMoreButton} = useItemsShowing(limit, totalCount)
</script>

<template>
  <p>
    <strong>This should update --></strong> {{itemsShowing}}
  </p>
  
  <button v-if="showLoadMoreButton" @click="limit += 10">
    {{limit}}
  </button>
</template>

useItemsShowing.ts

import { ref } from 'vue'

export function useItemsShowing(
  limit = 10, 
  totalCount = 0,
) {
  const itemsShowing = ref('Showing 0 out of 0')
  const showLoadMoreButton = ref(true)
  
  let currentItems = 0

  if (limit.value >= totalCount) {
    currentItems = totalCount
    showLoadMoreButton.value = false
  } else {
    currentItems = limit.value
    showLoadMoreButton.value = true
  }

  itemsShowing.value = `Showing ${currentItems} out of ${totalCount}`

  return {
    itemsShowing,
    showLoadMoreButton,
  }
}

1 Answers

Use watchEffect around the code that updates the other refs based on limit.value. That code will automatically re-run whenever limit.value changes:

import { ref, watchEffect } from 'vue'

export function useItemsShowing(
  limit = 10, 
  totalCount = 0,
) {
  const itemsShowing = ref('Showing 0 out of 0')
  const showLoadMoreButton = ref(true)
  
  let currentItems = 0
     
  watchEffect(() => {
    if (limit.value >= totalCount) {
      currentItems = totalCount
      showLoadMoreButton.value = false
    } else {
      currentItems = limit.value
      showLoadMoreButton.value = true
    }

    itemsShowing.value = `Showing ${currentItems} out of ${totalCount}`
  })
  
  return {
    itemsShowing,
    showLoadMoreButton,
  }
}

demo

Related