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
defineProps
in the wrong way.defineProps
will return a reactive object (aProxy
), meansprops
is now reactive. Since you declare a newreactive
with yourprops.x
.dataInput
is a new reactive object that is initialized with value ofprops.x
(just value initialization, no reactivity here)That's why when
props
is changed,dataInput
is 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