Как создать универсальный компонент формы в Next.js 14 с помощью TypeScript и формы реагирования?

Вопрос:

Я работаю над приложением Next.js 13 с TypeScript и пытаюсь создать общий компонент формы, используя форму реагирования. Цель состоит в том, чтобы иметь единый компонент формы, который может обрабатывать формы разных типов, такие как отчеты, клиенты и пользователи. Каждый тип формы имеет свой набор полей, но операции с формой (сохранение, сброс, обновление, удаление) остаются одинаковыми для всех типов.

Вот упрощенная версия того, чего я пытаюсь достичь:

import { FC } from 'react';
import { useForm, SubmitHandler } from 'react-hook-form';

// Define different types of form data
type ReportFormData = {
  reportField: string;
};

type ClientFormData = {
  clientField: string;
};

type UserFormData = {
  userField: string;
};

// Define props for the generic form component
type FormProps<T> = {
  initialData: T;
  onSubmit: SubmitHandler<T>;
};

// Create the generic form component
const GenericForm: FC<FormProps> = ({ initialData, onSubmit }) => {
  const { register, handleSubmit, reset } = useForm({
    defaultValues: initialData,
  });

  const onSubmitHandler: SubmitHandler<T> = (data) => {
    onSubmit(data);
  };

  return (
    <form onSubmit = {handleSubmit(onSubmitHandler)}>
      {/* How can I conditionally render fields based on the type of data? */}
      {/* How to properly handle type checking in this scenario? */}
      
      {/* Placeholder for save operation */}
      <button type = "submit">Save</button>
      
      {/* Placeholder for reset operation */}
      <button type = "button" onClick = {() => reset(initialData)}>
        Reset
      </button>
      
      {/* Placeholder for update operation */}
      {/* Placeholder for delete operation */}
    </form>
  );
};

Проблема:

У меня возникла проблема с проверкой типа TypeScript в компоненте GenericForm. Поскольку реактивная форма требует точного ввода полей формы, я не могу просто использовать тип объединения для данных моей формы. Однако мне нужен компонент GenericForm, чтобы принимать различные типы исходных данных в зависимости от отображаемой формы.

Я не уверен, как правильно обрабатывать проверку типов и условную отрисовку в компоненте GenericForm, чтобы разместить различные типы данных формы, сохраняя при этом безопасность типов.

Ожидаемый результат:

Я ожидаю, что у меня будет один компонент GenericForm, который сможет обрабатывать формы разных типов, отображая соответствующие поля в зависимости от типа предоставленных исходных данных. Кроме того, мне нужно убедиться, что проверка типов TypeScript правильно обрабатывается внутри компонента.

Зод: сила проверки и преобразования данных
Зод: сила проверки и преобразования данных
Сегодня я хочу познакомить вас с библиотекой Zod и раскрыть некоторые ее особенности, например, возможности валидации и трансформации данных, а также...
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Мне нравится библиотека Mantine Component , но заставить ее работать без проблем с Remix бывает непросто.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
TypeScript против JavaScript
TypeScript против JavaScript
TypeScript vs JavaScript - в чем различия и какой из них выбрать?
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Не все нужно хранить на стороне сервера. Иногда все, что вам нужно, это постоянное хранилище на стороне клиента для хранения уникальных для клиента...
Что такое ленивая загрузка в Angular и как ее применять
Что такое ленивая загрузка в Angular и как ее применять
Ленивая загрузка - это техника, используемая в Angular для повышения производительности приложения путем загрузки модулей только тогда, когда они...
2
0
106
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы на правильном пути. Я бы продолжил то, что вы сделали, и заставил бы GenericForm привести общий аргумент.

Определите компонент следующим образом.

const GenericForm = <T,>({ initialData, onSubmit }:FormProps<T>) => {

Тогда используйте его вот так <GenericForm<ReportFormData> initialData = {{reportField:""}} onSubmit = {()=>{}}/>

Это должно сделать GenericForm безопасным для типов initialData и onSubmit.

Вот пример с игровой площадки TS https://tsplay.dev/WG05vw

import React from 'react';
import { useForm, SubmitHandler, FieldValues, DefaultValues } from 'react-hook-form';

// Define different types of form data
type ReportFormData = {
  reportField: string | null;
};

type ClientFormData = {
  clientField: string | null;
};

type UserFormData = {
  userField: string | null;
};

// Define props for the generic form component 
type FormProps<T extends FieldValues> = {
  initialData: DefaultValues<T>;
  onSubmit: SubmitHandler<T>;
};

// Create the generic form component
const GenericForm =<T extends FieldValues,> ({ initialData, onSubmit }:FormProps<T>) => {
  const { register, handleSubmit, reset } = useForm<T>({
    defaultValues: initialData,
  });

  const onSubmitHandler: SubmitHandler<T> = (data) => {
    onSubmit(data);
  };

  return (
    <form onSubmit = {handleSubmit(onSubmitHandler)}>
      {/* How can I conditionally render fields based on the type of data? */}
      {/* How to properly handle type checking in this scenario? */}
      
      {/* Placeholder for save operation */}
      <button type = "submit">Save</button>
      
      {/* Placeholder for reset operation */}
      <button type = "button" onClick = {() => reset(initialData)}>
        Reset
      </button>
      
      {/* Placeholder for update operation */}
      {/* Placeholder for delete operation */}
    </form>
  );
};


const ReportFormComponent = () =>{

  return <GenericForm<ReportFormData> initialData = {{reportField:null}} onSubmit = {(data)=>console.info(data)}/>
}

Спасибо, но как насчет useForm ``` const form = useForm<T>({solver: zodResolver(InitialReportValidationSchema), defaultValues: report, }); ``` он не принимает ничего общего

Aladdin Mhemed 28.04.2024 08:21

Я добавил код и ссылку на игровую площадку TS, показывающую один из способов порадовать useForm принятием дженерика.

Scott Z 28.04.2024 15:31

Другие вопросы по теме