Skip to content

Combobox vNext: update useOptionCollection to use DOM ordering instead of React.Children#22572

Merged
smhigley merged 6 commits into
microsoft:masterfrom
smhigley:combobox-dom-ordering
May 11, 2022
Merged

Combobox vNext: update useOptionCollection to use DOM ordering instead of React.Children#22572
smhigley merged 6 commits into
microsoft:masterfrom
smhigley:combobox-dom-ordering

Conversation

@smhigley

Copy link
Copy Markdown
Contributor

Resolves #22055

I also added a story to show that this works when wrapping OptionGroup and Option.

The most relevant changes are in useOptionCollection.ts and useOption.tsx

@smhigley smhigley force-pushed the combobox-dom-ordering branch from ea69d1e to c4def5d Compare April 20, 2022 19:51
@codesandbox-ci

codesandbox-ci Bot commented Apr 20, 2022

Copy link
Copy Markdown

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit e3bf0e8:

Sandbox Source
@fluentui/react 8 starter Configuration
@fluentui/react-components 9 starter Configuration
quirky-shockley-cemjxv Issue #22055
headless-meadow-qs44hz Issue #22055

@fabricteam

fabricteam commented Apr 20, 2022

Copy link
Copy Markdown
Collaborator

📊 Bundle size report

Package & Exports Baseline (minified/GZIP) PR Change
react-combobox
Combobox
60.564 kB
20.751 kB
60.138 kB
20.636 kB
-426 B
-115 B

🤖 This report was generated against c416a93f71a2a4e9b78fbed720750c275a8cd4ae

@size-auditor

size-auditor Bot commented Apr 20, 2022

Copy link
Copy Markdown

Asset size changes

Size Auditor did not detect a change in bundle size for any component!

Baseline commit: c416a93f71a2a4e9b78fbed720750c275a8cd4ae (build)

@smhigley smhigley marked this pull request as ready for review April 25, 2022 20:31
@smhigley smhigley requested a review from a team as a code owner April 25, 2022 20:31
}

// use the DOM method compareDocumentPosition to order the current node against registered nodes
return Boolean(node.element.compareDocumentPosition(element) === Node.DOCUMENT_POSITION_PRECEDING);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I find myself a bit wary of this because we're maintaining internal component state based on the state of rendered DOM which feels backward from the typical React equation of UI = f(state) (where UI is the rendered DOM).

A similar pattern has proven to be a problem Fluent UI v8's List virtualization implementation where DOM measurements are cached in React state but not always updated, leading to scrolling issues.

That said, I don't see any specific issues here, plus this is an internal implementation detail so it could be changed later should it cause problems.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

IMO most of the DOM related stuff on our end tends to be because of our interesting perf stance which is to reduce as many rerenders as possible. React would just say that re-renders are cheap and you should be happy to use them. It's a similar situation with overflow.

However I do agree, that we should always be skeptical when we see native DOM being used in react

Comment thread packages/react-combobox/src/utils/OptionCollection.types.ts Outdated

@layershifter layershifter left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It's a huge step forward, great job 🚀

Comment thread packages/react-combobox/src/components/Listbox/useListbox.ts Outdated
Comment thread packages/react-combobox/src/components/Option/__snapshots__/Option.test.tsx.snap Outdated
Comment thread packages/react-combobox/src/utils/useOptionCollection.ts Outdated
Comment thread packages/react-combobox/src/utils/OptionCollection.types.ts Outdated
Comment thread packages/react-combobox/src/utils/useOptionCollection.ts Outdated
Comment thread packages/react-combobox/src/utils/Selection.types.ts
Comment thread packages/react-combobox/src/components/Option/useOption.tsx
Comment thread packages/react-combobox/src/components/Option/useOption.tsx Outdated
Comment thread packages/react-combobox/src/components/Listbox/useListbox.ts Outdated
Comment thread packages/react-combobox/src/components/Option/useOption.tsx Outdated
@layershifter

Copy link
Copy Markdown
Member

This is not related to this PR, but I was also checking what happens with keyboard actions:

image

We have double rendering for every option even with the latest suggestions. I debugged it and it's happening because onOptionClick in packages/react-combobox/src/components/Combobox/useCombobox.ts is unstable:

-  const onOptionClick = (event: React.MouseEvent<HTMLElement>, option: OptionValue) => {
+  const onOptionClick = useEventCallback((event: React.MouseEvent<HTMLElement>, option: OptionValue) => {
    // clicked option should always become active option
    setActiveOption(getOptionById(option.id));

    // close on option click for single-select
    !multiselect && setOpen(event, false);

    // handle selection change
    selectOption(event, option);
-  };
+  });

With these changes the issue is solved 😉

Comment thread packages/react-combobox/src/utils/useOptionCollection.ts Outdated
Comment thread packages/react-combobox/src/utils/useOptionCollection.ts Outdated
Comment thread packages/react-combobox/src/utils/useOptionCollection.ts Outdated
@smhigley smhigley requested review from layershifter and ling1726 May 5, 2022 06:35
@smhigley smhigley merged commit c2e1a59 into microsoft:master May 11, 2022
rohitpagariya pushed a commit to rohitpagariya/fluentui that referenced this pull request May 12, 2022
marwan38 pushed a commit to marwan38/fluentui that referenced this pull request Jun 13, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Combobox vNext: investigate DOM-based activedescendant/option-ordering implementation

7 participants