【问题标题】:Input fields lose focus on each value change in a complex Formik form输入字段失去了对复杂 Formik 表单中每个值变化的关注
【发布时间】:2020-06-13 11:53:08
【问题描述】:

我正在构建一个需要复杂表单生成(来自 json/js 对象)的应用程序。

这是我正在构建的示例:https://codesandbox.io/s/formik-form-wizard-test-vcj1t

我的问题如下:

所有输入字段都失去了对每个值更改的关注


CodeSandbox 项目的文件夹结构如下(便于代码理解):

./src:

  • App.js - 生成所有表单的主文件(generateWizardSteps 是生成所有表单的主函数)。

  • formSetup.js - 这是一个定义表单配置的对象。我需要从这样的对象构建动态表单。该对象具有pages 数组(这些是向导的步骤),每个page 都有一个fields 数组(如输入、选择、复选框等)。反过来,每个field 都有props 属性。 props 是我作为道具传递给 React 组件的。

  • formComponents.js - 此文件包含我用于生成表单的所有表单字段 React 组件。

  • decorateWithFormik.js - 这个文件只是为了让App.js 更小一点。这只是 useFormik 装饰器。


表单是使用formik 库构建的。此外,由于我需要一个类似向导的表单,因此我为它找到了一个不错的库:formik-wizard-form

我查看了有关类似主题的 stackoverflow 问题,但找不到适合我需要的内容。许多问题/答案都是关于动态 key 道具的问题,但据我所知,我的是静态的(它们都取自最初的 formSetup 对象)。

我注意到的另一件事是我的表单在每次值更改时都会重新呈现,但我不确定这是否是个问题。


您能帮我弄清楚问题出在哪里,为什么会发生,以及如何让我的表单字段失去焦点?

【问题讨论】:

  • 我不知道为什么,但对于其他库来说似乎也很正常。至于解决方案,也许只是在onChange事件处理程序中添加一些focus process,如果有必要,将其设为HOC或服务就足够了。
  • @keikai 你能说得更具体些吗?我尝试使用inputRef.current.focus();onChange 处理程序添加到我的输入中,但这似乎不是解决方案,而且它重新定义了formik 提供的onChange 函数。我也尝试过调用 formik onChange,然后在我的 onChang 中执行 inputRef.current.focus();,但这也没有任何效果
  • 发生的情况是,在每个 onChange 事件 MyTextInput 卸载并重新安装,这就是输入模糊的原因。似乎 generateWizardSteps 导致...
  • 看起来您正在渲染步骤中创建组件。这意味着每次表单呈现时都会重新创建子组件,这会导致它们失去焦点。我建议退后一步,检查formik-wizard-form 在他们的示例中如何做到这一点:github.com/mjangir/formik-wizard-form/tree/master/examples/src
  • @SimonIngeson 好吧,formik-wizard-form 在他们的示例中分别创建了每个Step,即每个步骤都是预定义的并且不是动态创建的。如果我尝试使用“静态”Steps 创建向导表单,那么一切正常。但我需要使其动态化,即能够从不同的设置对象生成这样的表单,这就是为什么我不能使用“静态”Steps 并且需要在map 函数中动态创建它们。不可能做到这一点,一定有办法......但现在我找不到任何解决方案或方法不在渲染中重新创建组件

标签: javascript reactjs formik


【解决方案1】:

解决了问题

我已经删除了所有可能的组件创建代码,并将所有内容移到了formik-wizard-form 库提供的Step 组件的component 属性中。

这是我的工作解决方案:https://codesandbox.io/s/formik-form-wizard-test-lz3x7(希望这会对某人有所帮助)

非常感谢 cmets 部分的每一个人!


主要见解:

  1. 失去焦点意味着组件unmounts and remounts 每次。

  2. 每次更改的这种卸载/重新安装行为是由在另一个组件的 render 函数内创建组件引起的。因此,在每次重新渲染时,都会重新创建输入组件。


我的最终工作代码:

const MyForm = props => {
  return (
    <FormikWizardProvider {...props}>
      {renderProps => (
        <Wizard {...renderProps}>
          <StepsList>
            {formSetup.pages.map(page => (
              <Step
                title={page.name}
                key={page.name}
                component={() =>
                  page.fields.map(field => {
                    if (
                      field.props &&
                      field.props.visibilityCheckbox &&
                      !props.values[field.props.visibilityCheckbox]
                    ) {
                      return null;
                    }

                    const fieldProps = {
                      formik: props,
                      key: field.props.name,
                      ...field.props
                    };

                    switch (field.type) {
                      case "input":
                        return <MyTextInput {...fieldProps} />;
                      case "radio":
                        return <RadioButtonGroup {...fieldProps} />;
                      case "checkbox":
                        return <MyCheckbox {...fieldProps} />;
                      case "select":
                        return <MySelect {...fieldProps} />;

                      default:
                        return null;
                    }
                  })
                }
              />
            ))}
          </StepsList>
          <ButtonsList>
            <PreviousButton />
            <NextButton />
            <SubmitButton />
          </ButtonsList>
        </Wizard>
      )}
    </FormikWizardProvider>
  );
};

export default decorateWizardWithFormik(MyForm);

【讨论】:

  • 就在昨天,我在 Reddit 上读到人们对 formik 在每个输入上重新渲染这会降低大型表单的性能感到不满。现在街区的新孩子是react-hook-form.com
猜你喜欢
  • 2022-06-12
  • 2021-08-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-06
  • 1970-01-01
  • 2014-09-17
  • 2021-06-18
相关资源
最近更新 更多