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的校验逻辑,步骤如下:
明确react-password-checklist的规则参数
组件接受的rules是字符串数组,可选值为minLength、maxLength、uppercase、lowercase、number、specialChar,完全匹配我们的密码要求。定义匹配Zod规则的rules数组
直接声明对应规则的数组,并传递给组件,同时指定minLength、maxLength和specialChars参数,确保与Zod校验一致:
const passwordCheckRules = ['minLength', 'maxLength', 'uppercase', 'lowercase', 'number', 'specialChar'];
- 修正组件调用代码
替换原来错误的rules传递方式,补充必要的参数:
<PasswordChecklist value={getValues('password') || ''} rules={passwordCheckRules} minLength={8} maxLength={32} specialChars="!@#$%&*-" />
- 修正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
相关产品推荐
相关产品推荐

