3
\$\begingroup\$

I've created my own AutoComplete form element based on @nextui-org/autocomplete to be able to use it along with react-hook-form. I am relatively new at TS, at least on generics, so I am not sure if I am overusing generics or have any mistakes really.

// AutoComplete.tsx

import {
  Autocomplete as NUIAutocomplete,
  AutocompleteItem as NUIAutocompleteItem,
  AutocompleteProps as NUIAutocompleteProps,
} from '@nextui-org/autocomplete';
import { CollectionChildren } from '@react-types/shared';
import React from 'react';
import { Control, FieldValues, Path, useController } from 'react-hook-form';

interface IAutoCompleteProps<T extends FieldValues, K extends object>
  extends Omit<NUIAutocompleteProps, 'children' | 'defaultItems'> {
  name: Path<T>;
  control: Control<T>;
  defaultItems?: Iterable<K>;
  children: CollectionChildren<K>;
}

const AutoComplete = <T extends FieldValues, K extends object>({
  name,
  control,
  variant = 'underlined',
  ...otherProps
}: IAutoCompleteProps<T, K>) => {
  const controller = useController({ name, control });

  return (
    <NUIAutocomplete
      aria-label={name}
      onSelectionChange={(value) => {
        console.log('value', value);
        controller.field.onChange(value);
      }}
      onClear={() => controller.field.onChange('')}
      {...controller.field}
      variant={variant}
      {...otherProps}
    >
      {otherProps.children as CollectionChildren<object>}
    </NUIAutocomplete>
  );
};

export default AutoComplete;

export const AutoCompleteItem = NUIAutocompleteItem;

And this is how I use it:

// EditClassroom.jsx

'use client';

import { Classroom, Grade } from '@prisma/client';
import React, { useEffect } from 'react';
import { SubmitHandler, useForm } from 'react-hook-form';

import { trpc } from '@/app/_trpc/client';

import { translateErrors } from '@/lib/translations';

import AutoComplete, {
  AutoCompleteItem,
} from '@/components/ui/form/AutoComplete';

interface IEditClassroomProps {
  onFinish: () => void;
  classroom?: Classroom;
}

const EditClassroom = ({ onFinish, classroom }: IEditClassroomProps) => {

  // ...

  const { data: grades } = trpc.grade.list.useQuery({});

  const {
    register,
    handleSubmit,
    formState: { errors, isSubmitting },
    reset,
    watch,

    setValue,
    control,
  } = useForm<Classroom>();

  // ...
  
  return (
    <form onSubmit={handleSubmit(onSubmit)}>

      {/*...*/}

      <AutoComplete
        name={'gradeId'}
        defaultItems={grades.results}
        isRequired={true}
        selectedKey={watch('gradeId')}
        label={t('recordFields.grade')}
        errorMessage={translateErrors(tErrors, 'gradeId', errors.gradeId)}
        control={control}
      >
        {(grade) => {
          return (
            <AutoCompleteItem key={grade.id} textValue={grade.name}>
              {grade.name}
            </AutoCompleteItem>
          );
        }}
      </AutoComplete>

      {/*...*/}

    </form>
  );
};

export default EditClassroom;


\$\endgroup\$

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.