Closed5
GPT-4にReactのコードを書かせてみる
ReactでFormを作って
項目は以下
- password
言語はTypeScript、ライブラリはReact Hook Form、zod、tailwindを使って
submit時にAPIをpostして、400エラーが発生したらFormにエラーを表示して
Form.tsx
import React from 'react';
import { useForm, SubmitHandler, Controller } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
const schema = z.object({
email: z.string().email(),
password: z.string().min(8),
});
type FormData = z.infer<typeof schema>;
export const Form: React.FC = () => {
const {
register,
handleSubmit,
control,
formState: { errors },
} = useForm<FormData>({
resolver: zodResolver(schema),
});
const onSubmit: SubmitHandler<FormData> = async (data) => {
try {
const response = await fetch('YOUR_API_ENDPOINT', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data),
});
if (!response.ok && response.status === 400) {
console.error('Error 400: Bad Request');
// フォームにエラーを表示する処理をここに追加します
} else {
// 成功した場合の処理をここに追加します
}
} catch (error) {
console.error('Error:', error);
}
};
return (
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
<div>
<label htmlFor="email" className="block text-sm font-medium">
Email
</label>
<input
id="email"
type="email"
{...register('email')}
className={`w-full p-2 border ${
errors.email ? 'border-red-600' : 'border-gray-300'
}`}
/>
{errors.email && (
<p className="text-red-600 text-sm">{errors.email.message}</p>
)}
</div>
<div>
<label htmlFor="password" className="block text-sm font-medium">
Password
</label>
<input
id="password"
type="password"
{...register('password')}
className={`w-full p-2 border ${
errors.password ? 'border-red-600' : 'border-gray-300'
}`}
/>
{errors.password && (
<p className="text-red-600 text-sm">{errors.password.message}</p>
)}
</div>
<button
type="submit"
className="w-full p-2 bg-blue-600 text-white font-semibold"
>
Submit
</button>
</form>
);
};
パスワードは英大文字、英小文字、数字、記号を必須にして
const schema = z.object({
email: z.string().email(),
password: z
.string()
.refine(
(value) => /[A-Z]/.test(value),
'Password must contain at least one uppercase letter'
)
.refine(
(value) => /[a-z]/.test(value),
'Password must contain at least one lowercase letter'
)
.refine(
(value) => /[0-9]/.test(value),
'Password must contain at least one number'
)
.refine(
(value) => /[\W_]/.test(value),
'Password must contain at least one special character'
)
.min(8, 'Password must be at least 8 characters long'),
});
inputを汎用コンポーネント化してForm.tsxから使って
Input.tsx
import React from 'react';
import { UseFormRegister, FieldError } from 'react-hook-form';
type InputProps = {
id: string;
type: string;
label: string;
register: UseFormRegister<any>;
error?: FieldError;
};
export const Input: React.FC<InputProps> = ({ id, type, label, register, error }) => {
return (
<div>
<label htmlFor={id} className="block text-sm font-medium">
{label}
</label>
<input
id={id}
type={type}
{...register(id)}
className={`w-full p-2 border ${
error ? 'border-red-600' : 'border-gray-300'
}`}
/>
{error && <p className="text-red-600 text-sm">{error.message}</p>}
</div>
);
};
Form.tsx
import React from 'react';
import { useForm, SubmitHandler } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
import { Input } from './Input';
// ... schema, FormData, and onSubmit ...
export const Form: React.FC = () => {
const {
register,
handleSubmit,
formState: { errors },
} = useForm<FormData>({
resolver: zodResolver(schema),
});
return (
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
<Input
id="email"
type="email"
label="Email"
register={register}
error={errors.email}
/>
<Input
id="password"
type="password"
label="Password"
register={register}
error={errors.password}
/>
<button
type="submit"
className="w-full p-2 bg-blue-600 text-white font-semibold"
>
Submit
</button>
</form>
);
};
InputコンポーネントをFormFieldコンポーネントとInputコンポーネントに分割して
Input.tsx
import React from 'react';
type InputProps = {
id: string;
type: string;
register: any;
hasError: boolean;
};
export const Input: React.FC<InputProps> = ({ id, type, register, hasError }) => {
return (
<input
id={id}
type={type}
{...register}
className={`w-full p-2 border ${
hasError ? 'border-red-600' : 'border-gray-300'
}`}
/>
);
};
FormField.tsx
import React from 'react';
import { FieldError } from 'react-hook-form';
import { Input } from './Input';
type FormFieldProps = {
id: string;
type: string;
label: string;
register: any;
error?: FieldError;
};
export const FormField: React.FC<FormFieldProps> = ({ id, type, label, register, error }) => {
return (
<div>
<label htmlFor={id} className="block text-sm font-medium">
{label}
</label>
<Input id={id} type={type} register={register} hasError={!!error} />
{error && <p className="text-red-600 text-sm">{error.message}</p>}
</div>
);
};
Form.tsx
import React from 'react';
import { useForm, SubmitHandler } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
import { FormField } from './FormField';
// ... schema, FormData, and onSubmit ...
export const Form: React.FC = () => {
const {
register,
handleSubmit,
formState: { errors },
} = useForm<FormData>({
resolver: zodResolver(schema),
});
return (
<form onSubmit={handleSubmit(onSubmit)} className="space-y-4">
<FormField
id="email"
type="email"
label="Email"
register={register('email')}
error={errors.email}
/>
<FormField
id="password"
type="password"
label="Password"
register={register('password')}
error={errors.password}
/>
<button
type="submit"
className="w-full p-2 bg-blue-600 text-white font-semibold"
>
Submit
</button>
</form>
);
};
コンポーネントファイル内の定数、関数、型をファイル分割して
src/types.ts
import { z } from 'zod';
export const schema = z.object({
email: z.string().email(),
password: z
.string()
.refine(
(value) => /[A-Z]/.test(value),
'Password must contain at least one uppercase letter'
)
.refine(
(value) => /[a-z]/.test(value),
'Password must contain at least one lowercase letter'
)
.refine(
(value) => /[0-9]/.test(value),
'Password must contain at least one number'
)
.refine(
(value) => /[\W_]/.test(value),
'Password must contain at least one special character'
)
.min(8, 'Password must be at least 8 characters long'),
});
export type FormData = z.infer<typeof schema>;
src/utils.ts
現在、Form.tsx にユーティリティ関数はありませんが、将来的に追加する場合は、このファイルに追加します。
src/constants.ts
現在、Form.tsx に定数はありませんが、将来的に追加する場合は、このファイルに追加します。
Form.tsx
import React from 'react';
import { useForm, SubmitHandler } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { FormField } from './FormField';
import { FormData, schema } from './types';
// ... onSubmit and Form component ...
このスクラップは2023/03/16にクローズされました