You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React项目中如何结合Zod配置react-password-checklist校验规则?

解决react-password-checklist与Zod密码规则同步问题

问题说明

我需要用react-password-checklist组件展示密码是否符合Zod的userSchema规则,但无法从Zod中提取规则传递给组件的rules属性,尝试userSchema.shape.password.refine.rules时提示ZodEffects不存在shape属性。

密码要求:

  • 长度在8到32字符之间
  • 包含至少1个大写字母
  • 包含至少1个小写字母
  • 包含至少1个数字
  • 包含至少1个特殊字符(!@#$%&*-)

解决方案

Zod的校验器是通过链式调用构建的,没有暴露可直接提取的规则集合,因此需要手动同步react-password-checklist的规则与Zod的校验逻辑,步骤如下:

  1. 明确react-password-checklist的规则参数
    组件接受的rules是字符串数组,可选值为minLength、maxLength、uppercase、lowercase、number、specialChar,完全匹配我们的密码要求。

  2. 定义匹配Zod规则的rules数组
    直接声明对应规则的数组,并传递给组件,同时指定minLength、maxLength和specialChars参数,确保与Zod校验一致:

const passwordCheckRules = ['minLength', 'maxLength', 'uppercase', 'lowercase', 'number', 'specialChar'];
  1. 修正组件调用代码
    替换原来错误的rules传递方式,补充必要的参数:
<PasswordChecklist
  value={getValues('password') || ''}
  rules={passwordCheckRules}
  minLength={8}
  maxLength={32}
  specialChars="!@#$%&*-"
/>
  1. 修正Zod schema的正则错误
    原schema中[A- Za-z]包含多余空格,会导致允许空格字符,修正为[A-Za-z]并补充长度上限:
const userSchema = z
  .object({
    password: z
      .string()
      .min(8, '密码至少8个字符')
      .max(32, '密码最多32个字符')
      .regex(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[!@#$%&*-])[A-Za-z\d!@#$%&*-]{8,32}$/),
    confirmPassword: z.string(),
  })
  .refine((fields) => fields.password === fields.confirmPassword, {
    path: ['confirmPassword'],
    message: "密码不匹配"
  });

修改后的完整组件代码

import React from 'react';
import { useForm } from 'react-hook-form';
import { z } from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';
import userSchema from '../../schema/signup';
import PasswordChecklist from "react-password-checklist"
import {
  Button,
  Flex,
  Text,
  FormControl,
  FormLabel,
  Heading,
  Input,
  Stack,
  FormErrorMessage
} from '@chakra-ui/react';

// 定义表单数据类型
type FormData = z.infer<typeof userSchema>;

export const SignUp = () => {
  const {
    register,
    handleSubmit,
    getValues,
    formState: { errors, isValid }
  } = useForm<FormData>({
    resolver: zodResolver(userSchema)
  });

  // 处理表单提交
  const handleForm = (data: FormData) => {
    console.log(data);
  };

  // 定义密码检查规则
  const passwordCheckRules = ['minLength', 'maxLength', 'uppercase', 'lowercase', 'number', 'specialChar'];

  return (
    <Stack minH={'100vh'} direction={{ base: 'column', lg: 'row' }}>
      <Flex p={8} flex={1} align={'center'} justify={'center'} bg="gray.300">
        <Stack spacing={4} w={'full'} maxW={'xl'}>
          <form onSubmit={handleSubmit(handleForm)}>
            <Heading fontSize={'2xl'}>注册账户</Heading>
            <FormControl id="password" isInvalid={!!errors.password}>
              <FormLabel>密码</FormLabel>
              <Input
                type="password"
                {...register('password')}
                placeholder="输入密码"
              />
              <FormErrorMessage>{errors.password?.message}</FormErrorMessage>
              <PasswordChecklist
                value={getValues('password') || ''}
                rules={passwordCheckRules}
                minLength={8}
                maxLength={32}
                specialChars="!@#$%&*-"
              />
            </FormControl>
            <FormControl
              id="confirm-password"
              isInvalid={!!errors.confirmPassword}
            >
              <FormLabel>确认密码</FormLabel>
              <Input
                type="password"
                {...register('confirmPassword')}
                placeholder="确认密码"
              />
              <FormErrorMessage>
                {errors.confirmPassword?.message}
              </FormErrorMessage>
            </FormControl>
            <Button
              colorScheme={'blue'}
              variant={'solid'}
              type="submit"
              disabled={!isValid}
            >
              注册
            </Button>
          </form>
        </Stack>
      </Flex>
    </Stack>
  );
};

补充说明

  • 确保react-password-checklist的specialChars参数与Zod正则中的特殊字符完全一致,避免两边校验结果不一致
  • 修正原代码中disabled={isValid}的逻辑错误,改为disabled={!isValid},即表单无效时禁用提交按钮
  • 添加FormData类型定义,提升TypeScript类型安全性

内容的提问来源于stack exchange,提问作者Begginer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 09:24:53