N
Nuxt6d ago
Kirito

Nuxt UI Pro : Custom component Maximum recursive updates exceeded

Hello I created a CommonsSelectMenu component that uses USelectMenu to avoid repeating code, but when I use it I get the error "Maximum recursive updates exceeded.", the error message is displayed locally but in production it freezes my app when I click on it. This is the content of my component :
<script setup lang="ts">
interface Props {
endpoint: string
placeholder?: string
searchable_attributes?: string | string[]
}

const {
endpoint,
placeholder,
searchable_attributes = 'name'
} = defineProps<Props>()

const { get } = useApi(endpoint)
const loading = ref(false)
const selected = ref([])
const emit = defineEmits(['update:modelValue'])

const search = async (q: string) => {
if (loading.value) return

loading.value = true

const items: any[] = await get(null, { q })

loading.value = false

return 'data' in items ? items.data : items
}
</script>

<template>
<USelectMenu
v-model="selected"
class="w-32"
:loading
:searchable="search"
searchable-placeholder="Rechercher..."
:placeholder="placeholder ?? 'Sélectionner'"
:option-attribute="searchable_attributes"
multiple
trailing
by="id"
:searchable-lazy="true"
@change="emit('update:modelValue', selected)"
>
<template #label>
<span
v-if="selected.length"
class="truncate"
>
{{ placeholder }}: {{ selected.length }}
</span>
</template>
</USelectMenu>
</template>
<script setup lang="ts">
interface Props {
endpoint: string
placeholder?: string
searchable_attributes?: string | string[]
}

const {
endpoint,
placeholder,
searchable_attributes = 'name'
} = defineProps<Props>()

const { get } = useApi(endpoint)
const loading = ref(false)
const selected = ref([])
const emit = defineEmits(['update:modelValue'])

const search = async (q: string) => {
if (loading.value) return

loading.value = true

const items: any[] = await get(null, { q })

loading.value = false

return 'data' in items ? items.data : items
}
</script>

<template>
<USelectMenu
v-model="selected"
class="w-32"
:loading
:searchable="search"
searchable-placeholder="Rechercher..."
:placeholder="placeholder ?? 'Sélectionner'"
:option-attribute="searchable_attributes"
multiple
trailing
by="id"
:searchable-lazy="true"
@change="emit('update:modelValue', selected)"
>
<template #label>
<span
v-if="selected.length"
class="truncate"
>
{{ placeholder }}: {{ selected.length }}
</span>
</template>
</USelectMenu>
</template>
The component is used this way : Script :
const filters = computed(() => ({
levels: levels.value.map(level => level.name).join(',')
}))

const debouncedFilters = useDebounce(filters, 300)

const { data } = await useAsyncData(
'lessons',
() =>
get(null, {
...(debouncedFilters.value.levels && { level: debouncedFilters.value.levels })
}),
{
watch: [debouncedFilters]
}
)
const filters = computed(() => ({
levels: levels.value.map(level => level.name).join(',')
}))

const debouncedFilters = useDebounce(filters, 300)

const { data } = await useAsyncData(
'lessons',
() =>
get(null, {
...(debouncedFilters.value.levels && { level: debouncedFilters.value.levels })
}),
{
watch: [debouncedFilters]
}
)
Template :
<CommonsSelectMenu @update:model-value="levels = $event" endpoint="levels" placeholder="Niveaux" />
<CommonsSelectMenu @update:model-value="levels = $event" endpoint="levels" placeholder="Niveaux" />
No description
No description
2 Replies
kapa.ai
kapa.ai6d ago
Hi @Kirito. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- Based on the information provided in your question and the available knowledge sources, I can offer some insights and suggestions regarding your Nuxt UI Pro custom component issue. The error "Maximum recursive updates exceeded" typically occurs when there's an infinite loop in the component's reactivity system. In your case, it seems that the issue might be related to how the component is updating its state and emitting changes. Here are a few suggestions to troubleshoot and potentially resolve the issue: 1. Avoid using v-model and @change together: Instead of using both v-model="selected" and @change="emit('update:modelValue', selected)" on the USelectMenu, try using only one of these methods. For example:
<USelectMenu
:model-value="selected"
@update:model-value="(val) => { selected = val; emit('update:modelValue', val) }"
...
>

<USelectMenu
:model-value="selected"
@update:model-value="(val) => { selected = val; emit('update:modelValue', val) }"
...
>

This approach ensures that you're not creating a circular update pattern. 2. Use toRefs for props: If you're using the selected value from props, make sure to use toRefs to maintain reactivity without causing unexpected updates:
<script setup lang="ts">
import { toRefs } from 'vue'

const props = defineProps<Props>()
const { modelValue } = toRefs(props)
const selected = ref(modelValue.value || [])
</script>

<script setup lang="ts">
import { toRefs } from 'vue'

const props = defineProps<Props>()
const { modelValue } = toRefs(props)
const selected = ref(modelValue.value || [])
</script>

3. Debounce the search function: To prevent rapid successive calls to the search function, consider debouncing it:
<script setup lang="ts">
import { useDebounceFn } from '@vueuse/core'

const debouncedSearch = useDebounceFn(async (q: string) => {
if (loading.value) return

loading.value = true
const items: any[] = await get(null, { q })
loading.value = false

return 'data' in items ? items.data : items
}, 300)
</script>

<script setup lang="ts">
import { useDebounceFn } from '@vueuse/core'

const debouncedSearch = useDebounceFn(async (q: string) => {
if (loading.value) return

loading.value = true
const items: any[] = await get(null, { q })
loading.value = false

return 'data' in items ? items.data : items
}, 300)
</script>

Then use debouncedSearch instead of search in your template. 4. Check for circular dependencies: Ensure that there are no circular dependencies between your components or in your data flow. 5. Verify the useApi implementation: Make sure that your useApi composable is implemented correctly and doesn't cause unexpected reactivity issues. If these suggestions don't resolve the issue, you might want to create a minimal reproducible example and seek further assistance from the Nuxt community or file an issue on the Nuxt UI GitHub repository (https://github.com/nuxt/ui/issues). It's worth noting that the error you're experiencing is not a common issue with Nuxt UI Pro components, so it's likely related to the specific implementation of your custom component or how it interacts with other parts of your application. Nuxt UI Pro Getting Started (https://ui.nuxt.com/pro/getting-started) documentation might provide additional insights on best practices for using Nuxt UI Pro components. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai6d ago
<@339342482326421505> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Want results from more Discord servers?
Add your server