第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號安全,請及時綁定郵箱和手機(jī)立即綁定

在React中使用TypeScript和Zod構(gòu)建自定義表單處理方案

標(biāo)簽:
前端工具 React Typescript

React 提供了许多库,例如 Formik、React Hook Form 和 Redux Form,用于管理表单。然而,构建自定义表单解决方案在某些情况下更为有利。本文将重点介绍如何使用 TypeScriptZod 构建一个可重用且类型安全的表单解决方案,并进行模式验证。

对为什么要进行自定义表单管理感到好奇?
  • 轻量且灵活:避免让应用程序因引入大型库而变得臃肿。
  • 细粒度控制:只需实现你需要的功能。
  • 全面的类型安全:集成 TypeScript 可以帮助你在开发过程中捕捉错误。
  • 自定义功能:根据你的使用场景添加特定逻辑。
Zod是什么东西?

Zod 是一个以 TypeScript 优先的模式验证库。它帮助定义和验证数据结构,提供了一个简洁直观的 API。

一个步骤指南:一步一步的指南:
1. 建立项目

首先,安装必要的依赖项:

    npm install zod react  
    npm install --save-dev @types/react
2. 使用 Zod 定义表单模式。
    import { z } from "zod";  

    const userSchema = z.object({  
      name: z.string().min(1, "名字是必填项"),  
      email: z.string().email("无效的电子邮件地址"),  
      age: z.number().min(18, "必须年满18岁"),  
    });  

    // 推断 TypeScript 类型  
    type UserFormValues = z.infer<typeof userSchema>;

这个方案确保了:

  • name 是一个非空的字符串。
  • email 必须是有效的电子邮件地址。
  • age 必须是数字,且至少为 18。
3. 构建自定义钩子来处理表单
    ```jsx
    // 导入React的useState和Zod的ZodError
    import { useState } from "react";  
    import { ZodError } from "zod";  

    // 定义一个useForm的函数,接受一个模式schema和初始值initialValues
    export function useForm<T>(schema: z.ZodSchema<T>, initialValues: T) {  
      // 使用useState来跟踪表单的值和错误
      const [values, setValues] = useState(initialValues);  
      const [errors, setErrors] = useState<Partial<Record<keyof T, string>>>({});  

      // 定义一个handleChange的函数,用于处理表单输入变化
      const handleChange = (key: keyof T) => (event: React.ChangeEvent<HTMLInputElement>) => {  
        setValues({ ...values, [key]: event.target.value });  
      };  

      // 定义一个validate的函数,用于验证表单数据
      const validate = () => {  
        try {  
          // 使用schema进行验证
          schema.parse(values);  
          // 如果验证通过,清除错误信息
          setErrors({});  
          return true;  
        } catch (e) {  
          // 如果验证失败,检查是否是ZodError
          if (e instanceof ZodError) {  
            // 获取错误信息
            const fieldErrors = e.errors.reduce((acc, error) => {  
              // 将错误信息存储在acc中
              acc[error.path[0] as keyof T] = error.message;  
              return acc;  
            }, {} as Partial<Record<keyof T, string>>);  
            // 设置错误信息
            setErrors(fieldErrors);  
          }  
          return false;  
        }  
      };  

      // 定义一个handleSubmit的函数,用于处理表单提交
      const handleSubmit = (onSubmit: (values: T) => void) => (event: React.FormEvent) => {  
        // 阻止表单的默认行为
        event.preventDefault();  
        // 如果验证通过,则调用onSubmit函数
        if (validate()) {  
          onSubmit(values);  
        }  
      };  

      // 返回值,错误,handleChange和handleSubmit
      return {  
        values,  
        errors,  
        handleChange,  
        handleSubmit,  
      };  
    }

## 4\. 创建 React 组件

import React from "react";
import { useForm } from "./useForm";
import { userSchema } from "./schemas";

const UserForm = () => {
const initialValues = { name: "", email: "", age: 18 };
const { values, errors, handleChange, handleSubmit } = useForm(userSchema, initialValues);

const onSubmit = (data: typeof initialValues) => {
console.log("已提交:", data);
};

return (
<form onSubmit={handleSubmit(onSubmit)}>
<div>
<label>名字</label>
<input
type="text"
value={values.name}
onChange={handleChange("name")}
/>
{errors.name && <p>{errors.name}</p>}
</div>
<div>
<label>电子邮件</label>
<input
type="email"
value={values.email}
onChange={handleChange("email")}
/>
{errors.email && <p>{errors.email}</p>}
</div>
<div>
<label>年纪</label>
<input
type="number"
value={values.age}
onChange={handleChange("age")}
/>
{errors.age && <p>{errors.age}</p>}
</div>
<button type="submit">提交按钮</button>
</form>
);
};

export default UserForm;


## 如下关键特性

1. **动态错误处理**:错误会显示在其相应的字段附近,以提升用户体验。
2. **可重复使用的逻辑**:`useForm` 钩子可以处理任何通过 Zod 定义的表单模式。
3. **全面类型保障**:Zod 确保表单数据符合模式,从而减少运行时错误。

## 5\. 添加一些高级特性

* **异步验证(例如,检查邮箱是否已被注册)**:用于服务器端验证。
* **动态字段**:根据用户行为动态添加或删除表单字段。
* **与库的集成**:使用 Tailwind 进行样式设计,或添加 Toast 通知以增强用户体验。

例子:添加异步校验

## 第一步:更新架构

添加一个名为 `refine` 的功能来对 `email` 字段执行异步验证。
import { z } from "zod";  

// 检查邮箱是否存在的模拟 API 调用  
const checkEmailExists = async (email: string) => {  
  return new Promise<boolean>((resolve) => {  
    setTimeout(() => {  
      resolve(email === "test@example.com"); // 模拟一个存在的邮箱  
    }, 1000);  
  });  
};  

// 带邮箱验证的异步模式  
const asyncSchema = z.object({  
  name: z.string().min(1, "名字是必填项"),  
  email: z  
    .string()  
    .email("无效的邮箱地址")  
    .refine(  
      async (email) => !(await checkEmailExists(email)),  
      "邮箱已被使用"  
    ),  
  password: z.string().optional(),  
  confirmPassword: z  
    .string()  
    .optional()  
    .refine(  
      (value, ctx) => {  
        if (!value && ctx.parent.password) {  
          return false;  
        }  
        return value === ctx.parent.password;  
      },  
      "密码必须一致"  
    ),  
});  

export type AsyncFormValues = z.infer<typeof asyncSchema>;

步骤 2:更新 `useForm` 钩子函数

为了支持动态字段,我们可以通过模式校验来进行条件更新。
导入 { useState } from "react";  
导入 { ZodError } from "zod";  

出口函数 useForm<T>(schema: z.ZodSchema<T>, initialValues: T) {  
  const [values, setValues] = useState(initialValues);  
  const [errors, setErrors] = useState<Partial<Record<keyof T, string>>>({});  
  const [loading, setLoading] = useState(false);  

  const handleChange = (key: keyof T) => async (event: React.ChangeEvent<HTMLInputElement>) => {  
    const updatedValues = { ...values, [key]: event.target.value };  
    setValues(updatedValues);  

    如果 (key === "email") {  
      setLoading(true);  
      尝试 {  
        等待 schema.parseAsync(updatedValues);  
        setErrors({});  
      } 捕获 (e) {  
        如果 (e instanceof ZodError) {  
          const fieldErrors = e.errors.reduce((acc, error) => {  
            acc[error.path[0] as keyof T] = error.message;  
            返回 acc;  
          }, {} as Partial<Record<keyof T, string>>);  
          setErrors(fieldErrors);  
        }  
      }  
      setLoading(false);  
    }  
  };  

  const validate = async () => {  
    尝试 {  
      等待 schema.parseAsync(values);  
      setErrors({});  
      返回 true;  
    } 捕获 (e) {  
      如果 (e instanceof ZodError) {  
        const fieldErrors = e.errors.reduce((acc, error) => {  
          acc[error.path[0] as keyof T] = error.message;  
          返回 acc;  
        }, {} as Partial<Record<keyof T, string>>);  
        setErrors(fieldErrors);  
      }  
      返回 false;  
    }  
  };  

  const handleSubmit = (onSubmit: (values: T) => void) => async (event: React.FormEvent) => {  
    event.preventDefault();  
    如果 (await validate()) {  
      onSubmit(values);  
    }  
  };  

  返回 {  
    values,  
    errors,  
    loading,  
    handleChange,  
    handleSubmit,  
  };  
}

### 步骤 3:创建动态表单

使用更新后的 `useForm` 钩子来创建一个动态表单,字段根据条件显示。
import React from "react";  
import { useForm } from "./useForm";  
import { asyncSchema, AsyncFormValues } from "./schemas";  

const DynamicForm = () => {  
  const initialValues: AsyncFormValues = {  
    name: "",  
    email: "",  
    password: "",  
    confirmPassword: "",  
  };  
  const { values, errors, loading, handleChange, handleSubmit } = useForm(asyncSchema, initialValues);  

  const onSubmit = (data: AsyncFormValues) => {  
    console.log("提交表单:", data);  
  };  

  return (  
    <form onSubmit={handleSubmit(onSubmit)}>  
      <div>  
        <label>姓名:</label>  
        <input  
          type="text"  
          value={values.name}  
          onChange={handleChange("name")}  
        />  
        {errors.name && <p>错误信息: {errors.name}</p>}  
      </div>  
      <div>  
        <label>邮箱</label>  
        <input  
          type="email"  
          value={values.email}  
          onChange={handleChange("email")}  
        />  
        {loading && <p>正在验证邮箱...</p>}  
        {errors.email && <p>错误信息: {errors.email}</p>}  
      </div>  
      {values.email && !errors.email && (  
        <>  
          <div>  
            <label>密码</label>  
            <input  
              type="password"  
              value={values.password}  
              onChange={handleChange("password")}  
            />  
          </div>  
          <div>  
            <label>确认密码</label>  
            <input  
              type="password"  
              value={values.confirmPassword}  
              onChange={handleChange("confirmPassword")}  
            />  
            {errors.confirmPassword && <p>错误信息: {errors.confirmPassword}</p>}  
          </div>  
        </>  
      )}  
      <button type="submit" disabled={loading}>  
        提交表单  
      </button>  
    </form>  
  );  
};  

export default DynamicForm;


# 它是怎么工作的

**动态字段显示**:

* 只有在电子邮件验证成功之后,才会显示密码框和确认密码框。
* 这样可以改善使用体验,减少用户认知负担。

**异步校验** :

* 通过 `checkEmailExists` 异步地进行邮箱验证。

**异常处理**

  每个字段的错误会在上下文中显示。

# 结论部分

用 React、TypeScript 和 Zod 构建自定义表单解决方案提供轻量且灵活的处理,并具备类型安全功能。虽然像 Formik 和 React Hook Form 这样的库非常出色,但自定义解决方案在需要完全控制表单时更占优势。

[来杯咖啡支持我](https://buymeacoffee.com/guestdm)
點擊查看更多內(nèi)容
TA 點贊

若覺得本文不錯,就分享一下吧!

評論

作者其他優(yōu)質(zhì)文章

正在加載中
  • 推薦
  • 評論
  • 收藏
  • 共同學(xué)習(xí),寫下你的評論
感謝您的支持,我會繼續(xù)努力的~
掃碼打賞,你說多少就多少
贊賞金額會直接到老師賬戶
支付方式
打開微信掃一掃,即可進(jìn)行掃碼打賞哦
今天注冊有機(jī)會得

100積分直接送

付費(fèi)專欄免費(fèi)學(xué)

大額優(yōu)惠券免費(fèi)領(lǐng)

立即參與 放棄機(jī)會
微信客服

購課補(bǔ)貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動學(xué)習(xí)伙伴

公眾號

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號

舉報

0/150
提交
取消