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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Autocomplete] useLayoutEffect in combobox #4015

Merged
merged 2 commits into from Feb 24, 2021
Merged

Conversation

dfmcphee
Copy link
Contributor

WHY are these changes introduced?

This fixes #3048.

Before this change
Screen Shot 2021-02-24 at 9 59 04 AM

After this change
Screen Shot 2021-02-24 at 9 58 26 AM

WHAT is this pull request doing?

It updates the effect used in the Combobox component to useLayoutEffect instead of useEffect. This makes sure the changes are committed before the browser paint cycle. This resolves the issue we were seeing in the autocomplete because it makes sure that change is updated before the popover tries to calculate the height to display itself.

How to 馃帺

Copy-paste this code in playground/Playground.tsx:
import React, {useCallback, useState, useMemo} from 'react';
import {SearchMinor} from '@shopify/polaris-icons';

import {Icon, Autocomplete, TextContainer} from '../src';

export function Playground() {
  const deselectedOptions = useMemo(
    () => [
      {value: 'rustic', label: 'Rustic'},
      {value: 'antique', label: 'Antique'},
      {value: 'vinyl', label: 'Vinyl'},
      {value: 'vintage', label: 'Vintage'},
      {value: 'refurbished', label: 'Refurbished'},
    ],
    [],
  );
  const [selectedOptions, setSelectedOptions] = useState([]);
  const [inputValue, setInputValue] = useState('');
  const [options, setOptions] = useState(deselectedOptions);
  const [loading, setLoading] = useState(false);

  const updateText = useCallback(
    (value) => {
      setInputValue(value);

      if (!loading) {
        setLoading(true);
      }

      setTimeout(() => {
        if (value === '') {
          setOptions(deselectedOptions);
          setLoading(false);
          return;
        }
        const filterRegex = new RegExp(value, 'i');
        const resultOptions = options.filter((option) =>
          option.label.match(filterRegex),
        );
        setOptions(resultOptions);
        setLoading(false);
      }, 300);
    },
    [deselectedOptions, loading, options],
  );

  const updateSelection = useCallback(
    (selected) => {
      const selectedText = selected.map((selectedItem) => {
        const matchedOption = options.find((option) => {
          return option.value.match(selectedItem);
        });
        return matchedOption && matchedOption.label;
      });
      setSelectedOptions(selected);
      setInputValue(selectedText);
    },
    [options],
  );

  const textField = (
    <Autocomplete.TextField
      onChange={updateText}
      label="Tags"
      value={inputValue}
      prefix={<Icon source={SearchMinor} color="subdued" />}
      placeholder="Search"
    />
  );

  const emptyState = (
    <>
      <Icon source={SearchMinor} />
      <div style={{textAlign: 'center'}}>
        <TextContainer>Could not find any results</TextContainer>
      </div>
    </>
  );

  return (
    <div style={{height: '225px'}}>
      <Autocomplete
        options={options}
        selected={selectedOptions}
        onSelect={updateSelection}
        loading={loading}
        textField={textField}
        emptyState={emptyState}
      />
    </div>
  );
}

馃帺 checklist

@github-actions
Copy link
Contributor

github-actions bot commented Feb 24, 2021

馃煝 This pull request modifies 2 files and might impact 1 other files.

Details:
All files potentially affected (total: 1)
馃搫 UNRELEASED.md (total: 0)

Files potentially affected (total: 0)

馃З src/components/Autocomplete/components/ComboBox/ComboBox.tsx (total: 1)

Files potentially affected (total: 1)

Copy link
Contributor

@kyledurand kyledurand left a comment

Choose a reason for hiding this comment

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

Nice, easy fix for a fairly ugly bug

@dfmcphee dfmcphee merged commit 37ce176 into main Feb 24, 2021
@dfmcphee dfmcphee deleted the fix-autocomplete-loading branch February 24, 2021 15:24
@BPScott
Copy link
Member

BPScott commented Feb 24, 2021

I seem to recall useLayoutEffect causes issues with server side rendering do we need to do something to make that play nice?

sylvhama pushed a commit that referenced this pull request Mar 26, 2021
* [Autocomplete] useLayoutEffect in combobox

* Adding to UNRELEASED
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.

Autocomplete with loading status is not working
3 participants