Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: Combobox - Maximum recursive updates exceeded #371

Closed
2 tasks
lassesbrt opened this issue Mar 3, 2024 · 16 comments
Closed
2 tasks

[Bug]: Combobox - Maximum recursive updates exceeded #371

lassesbrt opened this issue Mar 3, 2024 · 16 comments
Labels
bug Something isn't working

Comments

@lassesbrt
Copy link

Reproduction

https://stackblitz.com/edit/is2sf6?file=src%2FApp.vue

Describe the bug

Combobox is unable to render more than 100 elements. This can be easily reproduced when altering any combobox example from the docs to show more than 100 elements at a time.

Opening the popover results in the fallback to be displayed.

When opening the popover, this error message gets thrown in the browser console:
Maximum recursive updates exceeded. This means you have a reactive effect that is mutating its own dependencies and thus recursively triggering itself. Possible sources include component template, render function, updated hook or watcher source function.

I have read a bit about it and this radix-vue issue seems related:
unovue/radix-vue#551

System Info

System:
    OS: macOS 14.2
    CPU: (10) arm64 Apple M1 Pro
    Memory: 73.25 MB / 16.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 18.17.0 - ~/.nvm/versions/node/v18.17.0/bin/node
    npm: 9.6.7 - ~/.nvm/versions/node/v18.17.0/bin/npm
  Browsers:
    Chrome: 122.0.6261.94
    Firefox: 119.0
    Safari: 17.2
  npmPackages:
    @vueuse/core: ^10.9.0 => 10.9.0 
    radix-vue: ^1.4.9 => 1.4.9 
    vue: ^3.4.19 => 3.4.19

Contributes

  • I am willing to submit a PR to fix this issue
  • I am willing to submit a PR with failing tests
@lassesbrt lassesbrt added the bug Something isn't working label Mar 3, 2024
@a1danw
Copy link

a1danw commented Mar 19, 2024

I am also having the same issue. Is there a workaround?

@devbyray
Copy link
Contributor

devbyray commented Apr 3, 2024

I have this issue as well. I figured that until 100 items go fine, everything above 100 items will cause this issue 🤔

Check the example: https://stackblitz.com/~/github.com/devbyray/shadcn-vue-combobox-issue

@KeziahMoselle
Copy link

I'm also having this issue, I have ~100/200 items

@lazbeta
Copy link

lazbeta commented Apr 25, 2024

I'm also having this issue, 300 items

@rasco
Copy link

rasco commented Apr 25, 2024

same problem here. works for under ~100 items

@devbyray
Copy link
Contributor

It looks like it is fixed 💪🥳

@8uff3r
Copy link

8uff3r commented Apr 29, 2024

With the latest version of radix, it no longer shows this error but it's still VERY slow for larger lists.
I think ListboxVirtualizer may fix the issue but I don't know if it's directly usable here.

@lazbeta
Copy link

lazbeta commented Apr 29, 2024

the fix works for me!
maybe you can try this as workaround
Screenshot 2024-04-29 at 13 50 34

@felox2
Copy link

felox2 commented Jun 26, 2024

With the latest version of radix-vue (1.8.5) the issue is back: https://stackblitz.com/edit/is2sf6-qsxvsu?file=src%2FApp.vue
The error message is slightly different:
Uncaught (in promise) Maximum recursive updates exceeded in component <ComboboxInput>. This means you have a reactive effect that is mutating its own dependencies and thus recursively triggering itself. Possible sources include component template, render function, updated hook or watcher source function.

When you comment out the <CommandInput> the combobox works fine.

Any ideas?

@phuclh
Copy link

phuclh commented Jul 9, 2024

I have the same issue in v1.9.0

@Flowko
Copy link

Flowko commented Jul 10, 2024

a weird fix, for those using nuxt 3, go to CommandInput.vue and wrap the whole thing btween a ClientOnly component, like this:

<ClientOnly>
    <div class="flex items-center border-b px-3" cmdk-input-wrapper>
      <Search class="mr-2 size-4 shrink-0 opacity-50" />
      <ComboboxInput
        v-bind="{ ...forwardedProps, ...$attrs }"
        auto-focus
        :class="cn('flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50', props.class)"
      />
    </div>
  </ClientOnly>

somehow this fixes it and it works with larger arrays of items

@phuclh
Copy link

phuclh commented Jul 10, 2024

a weird fix, for those using nuxt 3, go to CommandInput.vue and wrap the whole thing btween a ClientOnly component, like this:

<ClientOnly>
    <div class="flex items-center border-b px-3" cmdk-input-wrapper>
      <Search class="mr-2 size-4 shrink-0 opacity-50" />
      <ComboboxInput
        v-bind="{ ...forwardedProps, ...$attrs }"
        auto-focus
        :class="cn('flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50', props.class)"
      />
    </div>
  </ClientOnly>

somehow this fixes it and it works with larger arrays of items

Do you have a fix for Vite?

@Flowko
Copy link

Flowko commented Jul 10, 2024

@phuclh maybe try to add const isBrowser = typeof window !== 'undefined'; and add it to the parent div as v-if="isBrowser" didnt test it, just speclating that this what clientOnly does in nuxt 3

@kikky7
Copy link
Contributor

kikky7 commented Jul 28, 2024

I have 1000 entries, getting same error, so I implemented solution provided by @lazbeta for now.
Probably would be optimized to implement async search for larger datasets, but I am not getting any lags while rendering the list (tested on local machine).

NOTE: using Inertia.js, not Nuxt

In script setup:

const usersComboboxOpen = ref(false);
const usersSearchTerm = ref("");
const users = usePage().props.users;
const userEntriesLimit = 50;
const filteredUsers = computed(() => {
  if (usersSearchTerm.value.length < 3) {
    return users.slice(0, userEntriesLimit);
  }

  const filtered = users.filter((user) =>
    user.label.toLowerCase().includes(usersSearchTerm.value.toLowerCase())
  );

  if (filtered.length > userEntriesLimit) {
    return filtered.slice(0, userEntriesLimit);
  }

  return filtered;
});

In template:

<Popover v-model:open="usersComboboxOpen">
  <PopoverTrigger as-child>
    <Button
      variant="outline"
      role="combobox"
      :aria-expanded="usersComboboxOpen"
      class="justify-between px-3"
    >
      {{
        form.user_id
          ? users.find((user) => user.value === form.user_id)?.label
          : "Select user..."
      }}
      <ChevronsUpDownIcon class="ml-2 size-4 shrink-0 opacity-50" />
    </Button>
  </PopoverTrigger>
  <PopoverContent class="p-0">
    <Command v-model:searchTerm="usersSearchTerm">
      <CommandInput
        class="h-9"
        placeholder="Search user..."
      />
      <CommandEmpty>No users found.</CommandEmpty>
      <CommandList
        <CommandGroup>
          <CommandItem
            v-for="user in filteredUsers"
            :key="user.value"
            :value="user.label"
            @select="
              () => {
                form.user_id = user.value;
                usersComboboxOpen = false;
              }
            "
          >
            {{ user.label }}
            <CheckIcon
              :class="
                cn(
                  'ml-auto size-4 shrink-0',
                  form.user_id === user.value
                    ? 'opacity-100'
                    : 'opacity-0'
                )
              "
            />
          </CommandItem>
        </CommandGroup>
      </CommandList>
    </Command>
  </PopoverContent>
</Popover>

@sadeghbarati
Copy link
Collaborator

Seems it's working good in v1.9.3, and it should be rendered better in v2

Closing as a stale issue

@sadeghbarati sadeghbarati closed this as not planned Won't fix, can't repro, duplicate, stale Aug 8, 2024
@kikky7
Copy link
Contributor

kikky7 commented Sep 4, 2024

I confirm it works with latest (1.9.5) version. Problem was in 1.9.1 for me. I tried with 1000 and 250 items and both work. The 1000 one has some minor "lag" so I still prefer the solution above which limits the entire list. 250 items is instant render.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests