Как создать асинхронный компонент автозаполнения (React

#javascript #reactjs #typescript #material-ui #react-hook-form

#javascript #reactjs #typescript #материал-пользовательский интерфейс #react-hook-form

Вопрос:

Я пытаюсь создать общий компонент автозаполнения с помощью компонента автозаполнения пользовательского интерфейса, react-hook-form и моих пользовательских хуков.

Что он должен делать: при вводе пользователем (после каждой буквы) должен быть вызов api, список параметров в автозаполнении должен быть соответствующим образом обновлен.

В чем моя проблема: многие повторные отправки дочерних и родительских компонентов (также при быстром вводе или удалении пользователем возникает некоторое отставание, скорее всего, связанное с повторными отправками). Я думаю, что должен быть способ избежать такого поведения с помощью react-hook-form, который я пытаюсь использовать, поскольку автозаполнения являются полями формы.

Может кто-нибудь сказать мне, что мой подход неправильный? Я не могу сильно изменить хук, содержащий вызов api. Может быть, у кого-то уже была подобная проблема? Я попытался обернуть автозаполнение mui с помощью контроллера из react-hook-form, но это не очень помогло. Компонент Location повторно отображается примерно 130 раз, когда пользователь вводит то, что он хочет, и удаляет его. Есть идеи, как заставить это работать?

Как это выглядит в настоящее время:

Компонент формы (с поставщиком RHF для контекста)

 import React from 'react';
import { useForm, FormProvider } from 'react-hook-form';

export default function UserForm(): JSX.Element {
  const methods = useForm();
  const handleSkip = (): void => {
    console.log('skipped');
  };

  const onSubmit = useCallback((rawFormData) => {
    console.log(rawFormData);
  }, []);

  return (
    <FormProvider {...methods}>
      <form onSubmit={methods.handleSubmit(onSubmit)}>
        <Location />
        <Actions>
          <SubmitButton isPending={false}>Submit</SubmitButton>
        </Actions>
      </Form>
    </FormProvider>
  );
}
  

Адреса:

 import React, { useState } from 'react';
import { useFormContext } from 'react-hook-form';

export default function Location(): JSX.Element {
  const { register } = useFormContext();
  const [selectedCountry, setSelectedCountry] = useState(null);
  const [nameOfCountry, setNameOfCountry] = useState('');
  const { data: countries} = useAutocomplete(nameOfCountry);


  return (
    <div>
      <CustomAutocomplete
        autocompleteOptions={countries}
        name='country'
        onInputChange={setSelectedCountry}
        placeholder='country'
        registerInput={register()}
      />
    </div>
  );
}
  

Пользовательское автозаполнение:

 import React, { SetStateAction, Dispatch, Ref, useState, useEffect } from 'react';
import { TextField } from '@material-ui/core';
import Autocomplete from '@material-ui/lab/Autocomplete';
import { useFormContext, Controller } from 'react-hook-form';

interface Properties {
  name: string;
  placeholder: string;
  autocompleteOptions: string[];
  onInputChange?: Dispatch<SetStateAction<string>>;
  onChange?: Dispatch<SetStateAction<string>>;
  isLoading?: boolean;
  registerInput: Ref<any>;
}

CustomAutocomplete.defaultProps = {
  isLoading: false,
  onChange: (value: Record<string, never>) => value,
  onInputChange: (value: string) => value,
};

export default function CustomAutocomplete({
  name,
  placeholder,
  autocompleteOptions,
  onInputChange,
  isLoading,
  onChange,
  registerInput,
}: Properties): JSX.Element {
  const { errors } = useFormContext();
  const options = autocompleteOptions || [];

  return (
    <div>
      <Autocomplete
        freeSolo
        getOptionLabel={(option: Country | string) => option.name || option}
        id="input-autocomplete"
        onInputChange={(event, value) => {
          onInputChange(value);
        }}
        openOnFocus={false}
        // onChange={(event, value) => onChange amp;amp; onChange(value) }
        options={options}
        renderInput={(parameters) => (
          <TextField
            {...parameters}
            error={Boolean(errors amp;amp; errors[name])}
            helperText={errors amp;amp; errors[name]?.message}
            id={name}
            inputRef={registerInput}
            name={name}
            placeholder={placeholder}
            rowsMax="1"
          />
        )}
      />
    </div>
  );
}
  

Используйте хук автозаполнения:

Содержит вызов api, который возвращает объект типа:

 {
//array of resuls
data: [],
isLoading: boolean
}