i have a vue component using the composition API that has some props passed into it.
i would like this component to pass its props into a composable that's a wrapper around useFetch, and i would like the composable to retain reactivity when the component's props change. i.e. i want useFetch to re-run when the props change.
the following works when i explicitly pass the props in as refs to the composable.
component:
<script setup lang="ts">
const props = defineProps({
page: {
default: 1,
required: false,
type: Number,
},
search: {
required: true,
type: String,
},
});
const { data, error, pending } = await useGetData(toRef(props, 'page'), toRef(props, 'search'));
</script>
composable:
export default (page: Ref<number>, search: Ref<string>) => {
const limit = ref(20);
const offset = computed(() => {
const p = page.value || 1;
return (p > 1) ? ((p - 1) * limit.value) : 0;
});
return useLazyFetch<DataIndex>('/api/data', {
query: {
limit,
offset,
search,
},
deep: false,
});
});
now, i would like to pass the props to my composable as an object instead of an ordered set of arguments. when i do this i seem to lose reactivity on the props - i.e. the query doesn't re-run when the props change in my component.
i've tried various interations of attempting to pass the props in as refs, but have had no luck.
component:
<script setup lang="ts">
const props = defineProps({
page: {
default: 1,
required: false,
type: Number,
},
search: {
required: true,
type: String,
},
});
const dataInput = reactive({
page: props.page,
search: props.search,
});
const { data, error, pending } = await useGetData(toRefs(dataInput));
</script>
composable:
interface GetDataInput {
page?: Ref<number>
search?: Ref<string>
};
export default (input: GetDataInput) => {
const limit = ref(20);
const offset = computed(() => {
const p = input.page?.value || 1;
return (p > 1) ? ((p - 1) * limit.value) : 0;
});
return useLazyFetch<DataIndex>('/api/data', {
query: {
limit,
offset,
search: input.search,
},
deep: false,
});
});
i assume that i'm losing reactivity in this example because either dataInput is not seeing the prop change, or because the input argument itself is not reactive when passed into the composable.
what am i missing here?
Your problem is using
definePropsin the wrong way.definePropswill return a reactive object (aProxy), meanspropsis now reactive. Since you declare a newreactivewith yourprops.x.dataInputis a new reactive object that is initialized with value ofprops.x(just value initialization, no reactivity here)That's why when
propsis changed,dataInputis kept intact cause they are not related or connected. Try to usetoRefs(props)insteadAnd for some reason, if you still want to keep
dataInput, try this instead