Reputation: 83
I am working with Nuxt 3 composition API using the Vue 3 script setup syntactic sugar.
I have an issue where refs from my composable isn't reactive once it has been returned to a component. Watching the value has no effect.
Take note that I am using VueUse to create different instances of the filedialog (useFileDialog).
import { useFileDialog } from '@vueuse/core'
import { ref as storageRef, getStorage, listAll, getDownloadURL, deleteObject } from 'firebase/storage'
import { useStorageFile } from 'vuefire'
import { ref, computed, watch } from 'vue'
export const useFileUpload = (props) => {
const storage = getStorage();
const filename = ref();
const fileRef = ref(null);
const selectedImages = ref([]);
const images = ref({});
const imagePreviews = computed(() => {
if (images.value) {
return Array.from(images.value).map(file => URL.createObjectURL(file));
}
return [];
})
const {
url,
uploadTask,
upload,
} = useStorageFile(fileRef)
const { files, open } = useFileDialog()
const { open: openMaterialer, files: materialerFiles } = useFileDialog();
const { open: openPlantegning, files: plantegningFiles } = useFileDialog();
watch(files, (newFiles) => {
if (newFiles.length > 0) {
const fileType = newFiles[0].type.split('/')[0]
if (fileType === 'image') {
images.value = newFiles
}
else return
}
})
const uploadFile = async () => {
// Some upload logic here
}
watchEffect(() => {
// Confirms reactivity in composable
console.log('materialerFiles in upload:', materialerFiles.value);
});
return {
imagePreviews,
files,
materialerFiles,
plantegningFiles,
uploadTask,
open,
openMaterialer,
openPlantegning,
uploadFile,
};
};
Now in my component i use the composable (remember that the composable is auto imported)
// files
const { files, materialerFiles, plantegningFiles } = useFileUpload()
// Watch for changes to materialerFiles
watch(materialerFiles, (newMaterialerFiles) => {
console.log('changed')
userInput.value = {
...userInput.value,
materialerFiles: newMaterialerFiles,
};
});
This should log 'changed' to the console from the component. But nothing happens.
Have i misunderstood something or is this a known issue. Any workarounds or suggestions?
I expect to log the files which should materilaerFiles should contain.
Steps to reproduce:
Upvotes: 2
Views: 1934
Reputation: 83
Okay I found the issue.
The issue lies in my misunderstanding of how composables work.
In my codebase I have a component which uses my composable to set the files, and another component where I wanted to use the composable to import the files which were set in the first component. This does not work due to the nature of how composables work.
In short, the issue was:
Scope of Composable Invocation:
When you invoke useYourComposable() in ComponentOne.vue, and useYourComposable() in ComponentTwo.vue, two separate instances of the composable are created. Each instance has its own separate state. Changes to state in one instance won't affect the same state in the other instance.
The solution:
In order to share state between different components, you'd have to use a state management solution. Someting like Pinia or Vuex (Pinia is the new standard for Vue3).
Upvotes: 6
Reputation: 1805
Currently you are setting a ref in userInput.value.materialerFiles, not the value of newMaterialerFiles ref.
Try update you watch by setting userInput.value using the value of materialerFiles ref like this:
// files
const { files, materialerFiles, plantegningFiles } = useFileUpload()
// Watch for changes to materialerFiles
watch(materialerFiles, (newMaterialerFiles) => {
console.log('changed')
userInput.value = {
...userInput.value,
materialerFiles: newMaterialerFiles.value,
};
});
Upvotes: 0