Felix
Felix

Reputation: 21

Vue.js composable loses reactivity

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 rerun 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

File 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>

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

Upvotes: 2

Views: 1778

Answers (1)

tony19
tony19

Reputation: 138696

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

Upvotes: 1

Related Questions