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

如何在React Storybook中强制Formik表单显示字段错误状态?

如何在React Storybook中触发所有表单字段的错误样式展示

嘿,这个需求我之前在项目里刚好碰到过,最简实现得看你用的表单库——毕竟React生态里常用的Formik和React Hook Form处理方式略有不同,我给你分别说下最直接的方案:

如果你用的是Formik

Formik提供了**initialTouched**属性,可以直接在初始化时把所有需要展示错误的字段标记为已触碰状态,这是最省事的方法,不用额外写逻辑:

import { Formik, Form, Field } from 'formik';
import * as Yup from 'yup';

// 你的验证规则
const validationSchema = Yup.object({
  email: Yup.string().email('无效邮箱格式').required('此字段必填'),
  password: Yup.string().min(6, '密码长度不能少于6位').required('此字段必填'),
});

export const FormWithAllErrorsVisible = () => (
  <Formik
    initialValues={{ email: '', password: '' }} // 你的初始值
    initialTouched={{ email: true, password: true }} // 关键:直接标记所有字段为已触碰
    validationSchema={validationSchema}
    onSubmit={() => {}} // Storybook里可以留空
  >
    {({ errors, touched }) => (
      <Form>
        <div className="form-field">
          <label>邮箱</label>
          <Field name="email" type="email" />
          {/* 原有的错误提示逻辑,现在会直接触发 */}
          {errors.email && touched.email && <span className="error-text">{errors.email}</span>}
        </div>
        <div className="form-field">
          <label>密码</label>
          <Field name="password" type="password" />
          {errors.password && touched.password && <span className="error-text">{errors.password}</span>}
        </div>
      </Form>
    )}
  </Formik>
);

如果你的字段很多,不想一个个写initialTouched,可以用Object.keys遍历初始值生成:

const initialValues = { email: '', password: '', username: '' };
const initialTouched = Object.fromEntries(Object.keys(initialValues).map(key => [key, true]));

如果你用的是React Hook Form

React Hook Form的话,有两种简单方式:

方式1:挂载后触发所有字段的验证(同时标记为已触碰)

利用trigger方法,在组件挂载时触发所有字段的验证,这样既会生成错误信息,也会把字段标记为已触碰:

import { useForm } from 'react-hook-form';

const LoginForm = () => {
  const { 
    register, 
    formState: { errors, touched },
    trigger // 引入trigger方法
  } = useForm({
    defaultValues: { email: '', password: '' },
    mode: 'onTouched' // 你的原验证模式
  });

  // Storybook专属逻辑:挂载时触发所有字段验证
  React.useEffect(() => {
    // 传入字段数组,触发验证并标记为已触碰
    trigger(['email', 'password']);
  }, [trigger]);

  return (
    <form>
      <div className="form-field">
        <label>邮箱</label>
        <input 
          {...register('email', {
            required: '此字段必填',
            pattern: { value: /^\S+@\S+$/i, message: '无效邮箱格式' }
          })} 
        />
        {errors.email && touched.email && <span className="error-text">{errors.email.message}</span>}
      </div>
      <div className="form-field">
        <label>密码</label>
        <input 
          {...register('password', {
            required: '此字段必填',
            minLength: { value: 6, message: '密码长度不能少于6位' }
          })} 
        />
        {errors.password && touched.password && <span className="error-text">{errors.password.message}</span>}
      </div>
    </form>
  );
};

export const FormWithAllErrorsVisible = () => <LoginForm />;

方式2:直接手动设置所有字段为已触碰

如果不想触发验证(比如初始值已经不符合规则),可以用setTouched方法直接标记:

import { useForm } from 'react-hook-form';

const LoginForm = () => {
  const { 
    register, 
    formState: { errors, touched },
    setTouched // 引入setTouched方法
  } = useForm({
    defaultValues: { email: '', password: '' },
    mode: 'onTouched'
  });

  React.useEffect(() => {
    // 直接标记所有字段为已触碰
    setTouched({ email: true, password: true });
  }, [setTouched]);

  // 后续表单渲染逻辑和上面一致...
};

总结

核心思路就是让所有字段的touched状态变为true,不管是初始化时直接设置,还是组件挂载后手动触发,都是围绕这个点来的。根据你用的表单库选对应的方案就行,这两种都是最简洁的实现方式,不需要额外封装复杂逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 03:49:52