3

I am using a composable to load images in Vue3. I have been able to pass all the props successfully as one object, see this question, but I am unable to pass the one property I want to be reactive. I am fairly certain that the issue is that the property in undefined

// loadImage.js
import { onMounted, ref, watch } from 'vue'

// by convention, composable function names start with "use"
export function useLoadImage(src) {
  let loading = ref(true)
  let show = ref(false)

  const delayShowImage = () => {
    setTimeout(() => {
      show.value = true
    }, 100)
  }
  const loadImage = (src) => {
    let img = new Image()
    img.onload = (e) => {
      loading.value = false
      img.onload = undefined
      img.src = undefined
      img = undefined
      delayShowImage()
    }
    img.src = src
  }
  onMounted(() => {
    if (src) {
      loadImage(src)
    }
  })
  watch(
    () => src,
    (val) => {
      if (val) {
        loading.value = true
        loadImage(val)
      }
    },
  )
  // expose managed state as return value
  /**
   * loading is the image is loading
   * show is a delayed show for images that transition.
   */
  return { loading, show }
}

The below method returns this in the console.log and does not error.

Proxy {src: undefined} undefined

<script setup>
import { defineProps, computed } from 'vue'
import { useLoadImage } from '../../composables/loadImage'

const props = defineProps({
  src: String
})

console.log(props, props.src)
const srcRef = computed(() => props.src)
const { loading, show } = useLoadImage(srcRef)
</script>

The below method returns this in the console.log

Proxy {src: undefined} undefined

and gives the following error

TypeError: Cannot read properties of undefined (reading 'undefined')

<script setup>
import { defineProps, toRef } from 'vue'
import { useLoadImage } from '../../composables/loadImage'

const props = defineProps({
  src: String
})

console.log(props, props.src)
const srcRef = toRef(props.src)
const { loading, show } = useLoadImage(srcRef)
</script>
3
  • 1
    It seems you're not passing the src props correctly to the component which is why it's returning undefined Commented May 27, 2022 at 21:14
  • @ibn_Abubakre The issue then is that it is not reactive. When the src updates, the composable does not. Commented May 27, 2022 at 21:52
  • See answer here -> stackoverflow.com/a/76196045/6385184 Commented May 7, 2023 at 20:09

1 Answer 1

8

As indicated in comments, it seems src is undefined in your component because you're probably not passing the prop correctly to the component.

Even if src were set with a string, there still would be a few other issues:

  1. toRef's first argument should be a reactive object (i.e., props), and the second argument should be the name of a key (i.e., 'src'):

    // MyComponent.vue
    
    const srcRef = toRef(props.src) ❌
    const srcRef = toRef(props, 'src') ✅
    

    Note: It's also valid to use const srcRef = computed(() => props.src), as you were originally doing.

  2. watch's first argument is a WatchSource. When WatchSource is a function dealing with a ref, it should return the ref's unwrapped value. Alternatively, the WatchSource can be the ref itself:

    // loadImage.js
    
    watch(() => srcRef, /* callback */) ❌
    watch(() => srcRef.value, /* callback */) ✅
    watch(srcRef, /* callback */) ✅
    
  3. The composable receives the image source in a ref, and your onMounted() hook is passing that ref to loadImage(), which is actually expecting the string in the ref's unwrapped value:

    // loadImage.js
    
    onMounted(() => {
      if (src) { ❌ /* src is a ref in this composable */
        loadImage(src)
      }
    })
    
    onMounted(() => {
      if (src.value) { ✅
        loadImage(src.value)
      }
    })
    

demo

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.