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

如何将Formik的field属性传入Storybook Story并解决未定义报错

Formik自定义TextField组件的Storybook报错:无法解构'field'的'name'属性,因为它未定义

自定义TextField组件代码

import { memo } from 'react';

import { OutlinedTextFieldProps } from '@mui/material/TextField';
import { InputAdornment, TextField as MuiTextField } from '@mui/material';
import { FieldProps } from 'formik';

interface TextFieldPropsInterface extends OutlinedTextFieldProps, FieldProps {
  validationErrors?: Record<string, string[]> | undefined;
  loading?: boolean;
  endAdornmentText?: string;
}

function TextField({
  loading,
  validationErrors,
  field,
  form,
  endAdornmentText,
  ...TextFieldProps
}: TextFieldPropsInterface) {
  const { name } = field;
  const { touched, errors } = form;
  const { helperText } = TextFieldProps;

  const hasError = touched[name] && Boolean(errors[name]);
  const errorMessage = errors && errors[name];

  return (
    <MuiTextField
      {...TextFieldProps}
      error={hasError}
      helperText={hasError ? errorMessage : helperText}
      disabled={loading || TextFieldProps?.disabled}
      InputProps={{
        endAdornment: endAdornmentText ? (
          <InputAdornment position='end'>{endAdornmentText}</InputAdornment>
        ) : null,
      }}
      {...field}
    />
  );
}

export default memo(TextField);

Storybook代码

import { ComponentStory, ComponentMeta, storiesOf } from '@storybook/react';
import { withFormik } from '@bbbtech/storybook-formik';

import FormikTextField from '.';

export default {
  component: FormikTextField,
  decorators: [withFormik],
} as unknown as ComponentMeta<typeof FormikTextField>;

const Template: ComponentStory<typeof FormikTextField> = (args) => (
  <FormikTextField {...args} />
);

export const Default = Template.bind({});

Default.args = {
  loading: false,
  validationErrors: undefined,
  endAdornmentText: 'End adornment',
};

报错信息

TypeError
Cannot destructure property 'name' of 'field' as it is undefined.
Call Stack
 TextField
  main.iframe.bundle.js:1497:5
 renderWithHooks
  vendors-node_modules_bbbtech_storybook-formik_dist_esm_index_js-node_modules_mui_icons-materi-41c387.iframe.bundle.js:116439:18
 mountIndeterminateComponent
  vendors-node_modules_bbbtech_storybook-formik_dist_esm_index_js-node_modules_mui_icons-materi-41c387.iframe.bundle.js:119265:13
 beginWork
  vendors-node_modules_bbbtech_storybook-formik_dist_esm_index_js-node_modules_mui_icons-materi-41c387.iframe.bundle.js:120503:16
 HTMLUnknownElement.callCallback
  vendors-node_modules_bbbtech_storybook-formik_dist_esm_index_js-node_modules_mui_icons-materi-41c387.iframe.bundle.js:105399:14
 Object.invokeGuardedCallbackDev
  vendors-node_modules_bbbtech_storybook-formik_dist_esm_index_js-node_modules_mui_icons-materi-41c387.iframe.bundle.js:105448:16
 invokeGuardedCallback
  vendors-node_modules_bbbtech_storybook-formik_dist_esm_index_js-node_modules_mui_icons-materi-41c387.iframe.bundle.js:105510:31
 beginWork$1
  vendors-node_modules_bbbtech_storybook-formik_dist_esm_index_js-node_modules_mui_icons-materi-41c387.iframe.bundle.js:125413:7
 performUnitOfWork
  vendors-node_modules_bbbtech_storybook-formik_dist_esm_index_js-node_modules_mui_icons-materi-41c387.iframe.bundle.js:124225:12
 workLoopSync
  vendors-node_modules_bbbtech_storybook-formik_dist_esm_index_js-node_modules_mui_icons-materi-41c387.iframe.bundle.js:124156:5

原因分析

自定义组件依赖Formik的FieldProps,必须由Formik的Field组件或withFormik装饰器注入field和form对象。当前报错是因为field属性未被正确传递,导致解构field.name时失败。

解决方案

方案1:完善Storybook的Formik配置,传递必要字段信息

@bbbtech/storybook-formik的withFormik装饰器需配置表单初始值,同时给组件指定name属性,修改后的Story代码如下:

import { ComponentStory, ComponentMeta } from '@storybook/react';
import { withFormik } from '@bbbtech/storybook-formik';

import FormikTextField from '.';

export default {
  component: FormikTextField,
  decorators: [withFormik],
  parameters: {
    formik: {
      initialValues: {
        username: '', // 定义表单初始值,字段名需和组件name对应
      },
    },
  },
} as unknown as ComponentMeta<typeof FormikTextField>;

const Template: ComponentStory<typeof FormikTextField> = (args) => (
  <FormikTextField {...args} />
);

export const Default = Template.bind({});

Default.args = {
  loading: false,
  validationErrors: undefined,
  endAdornmentText: 'End adornment',
  name: 'username', // 指定字段名,和initialValues中的key对应
};

方案2:给组件添加容错处理,防止field未定义

在组件中给field和form设置默认值,避免未注入时报错:

function TextField({
  loading,
  validationErrors,
  field = { name: '' }, // 添加默认值
  form = { touched: {}, errors: {} }, // 添加默认值
  endAdornmentText,
  ...TextFieldProps
}: TextFieldPropsInterface) {
  const { name } = field;
  const { touched, errors } = form;
  const { helperText } = TextFieldProps;

  const hasError = touched[name] && Boolean(errors[name]);
  const errorMessage = errors && errors[name];

  return (
    <MuiTextField
      {...TextFieldProps}
      error={hasError}
      helperText={hasError ? errorMessage : helperText}
      disabled={loading || TextFieldProps?.disabled}
      InputProps={{
        endAdornment: endAdornmentText ? (
          <InputAdornment position='end'>{endAdornmentText}</InputAdornment>
        ) : null,
      }}
      {...field}
    />
  );
}

方案3:改用Formik的Field组件包裹TextField

如果withFormik装饰器无法正确注入属性,可直接在Story模板中用Formik的Field组件包裹自定义TextField:

import { ComponentStory, ComponentMeta } from '@storybook/react';
import { Formik, Form, Field } from 'formik';

import FormikTextField from '.';

export default {
  component: FormikTextField,
} as unknown as ComponentMeta<typeof FormikTextField>;

const Template: ComponentStory<typeof FormikTextField> = (args) => (
  <Formik
    initialValues={{ username: '' }}
    onSubmit={() => {}}
  >
    <Form>
      <Field name="username" component={FormikTextField} {...args} />
    </Form>
  </Formik>
);

export const Default = Template.bind({});

Default.args = {
  loading: false,
  validationErrors: undefined,
  endAdornmentText: 'End adornment',
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 10:45:44