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

fix(multi-select): avoid cyclic dependency for Svelte 5 compatibility #2034

Merged

Conversation

malinowskip
Copy link
Contributor

@malinowskip malinowskip commented Nov 9, 2024

Fixes #1986

Here’s an attempt to fix the issues in the MultiSelect component that caused incompatibility with Svelte 5 by creating infinite loops (#1986). It seems like the core issue was the circular dependency between the items and sortedItems variables:

items assigned tosortedItems in an afterUpdate block:

sortedItems depends on items:

  $: sortedItems = items.map((item) => ({
    ...item,
    checked: selectedIds.includes(item.id),
  }));

The commit removes the sortedItems variable, which served an intermediate role, and changes are made to items directly.

Refactor the MultiSelect component to remove circular dependencies which
would cause infinite loops in Svelte 5 (carbon-design-system#1986).
if (!open) {
if (!initialSorted || selectionFeedback !== "fixed") {
sortedItems = sort();
$: if (!open) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inside afterUpdate, this block would cause an infinite loop.

sortedItems = sort();
$: if (!open) {
if (!initialSorted || selectionFeedback !== "fixed") {
tick().then(() => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tick ensures that the variables are instantiated when the sorting happens.

Copy link
Collaborator

@metonym metonym left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for taking the time to get this going. You're spot on in identifying the root issue of the infinite update loop in Svelte 5. There's a cyclical items <> sortedItems dependency in afterUpdate.

However, one thing I noticed is that this current change does not support initially set selectedIds.

<MultiSelect
  selectedIds={["0", "1"]}
  titleText="Contact"
  label="Select contact methods..."
  items={[
    { id: "0", text: "Slack" },
    { id: "1", text: "Email" },
    { id: "2", text: "Fax" },
  ]}
/>

@metonym
Copy link
Collaborator

metonym commented Nov 9, 2024

I've pushed a 6fbedab that does the following:

  • Remove the cyclical dependency in afterUpdate
  • Consolidate around sortedItems internally to avoid the cyclical dependency

I've so far tested with both Svelte 4 and Svelte 5.

@metonym metonym changed the title fix(multiselect): Svelte 5 compatibility fix(multi-select): fix reactivity for Svelte 5 compatibility Nov 9, 2024
@metonym metonym force-pushed the fix-multiselect-error branch from 6fbedab to fe7790b Compare November 9, 2024 21:51
@metonym metonym changed the title fix(multi-select): fix reactivity for Svelte 5 compatibility fix(multi-select): avoid cyclic dependency for Svelte 5 compatibility Nov 9, 2024
@metonym metonym merged commit 1acd713 into carbon-design-system:master Nov 9, 2024
1 check passed
@malinowskip
Copy link
Contributor Author

Thank for reviewing and catching the selectedIds issue. I think that your solution introduces one breaking change, though: the sorting logic doesn’t update the items variable, so the new sort order is not propagated to the parent (if items is bound reactively).

@brunnerh
Copy link
Contributor

Arguably that was a bug; the property was not marked as being reactive and who really wants this?

@malinowskip
Copy link
Contributor Author

It is marked as reactive in the docs (https://svelte.carbondesignsystem.com/components/MultiSelect#props), though, as you say, maybe it’s not useful for this prop to be reactive.

@brunnerh
Copy link
Contributor

Right, I forgot that the tags are generated based on usage, so they don't appear in the source code JSDoc.

@metonym
Copy link
Collaborator

metonym commented Nov 10, 2024

Arguably that was a bug; the property was not marked as being reactive and who really wants this?

Nice catch – MultiSelect items should not be reactive, and that was identified via this cyclic dependency fix. Generated docs need to be updated to reflect this – created #2042

@metonym
Copy link
Collaborator

metonym commented Nov 20, 2024

Released in v0.86.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Svelte 5] MultiSelect triggers effect_update_depth_exceeded error
3 participants