【问题标题】:Formik bug with re-rendering select value after changing更改后重新渲染选择值的 Formik 错误
【发布时间】:2021-10-06 10:25:27
【问题描述】:

我在 typescript web 应用程序中使用 formik 2.2.9,但我遇到了 html 选择元素的问题。

所以,我的表单有这样的控件:

export interface CriterionEdit {
    id: number;
    name: string;
    description: string;
    isDeleted: boolean;
    interval: number;
    groupId: number;
}

我写了这样的代码:

public render() {
    return (
      <React.Fragment>
        <h1>Edit</h1>

        <Formik
          enableReinitialize
          initialValues={this.props.criterion}
          onSubmit={(values) => {
            // https://github.com/formium/formik/issues/1191#issuecomment-607333552 waiting v 3.0.0
            values.interval = parseInt(values.interval as any, 10);
            values.groupId = parseInt(values.groupId as any, 10);
            values.isDeleted = (values.isDeleted as any) === "true";
            const requestOptions = {
              method: "POST",
              headers: { "Content-Type": "application/json" },
              body: JSON.stringify(values),
            };
            fetch("/criterion/update/", requestOptions).then(
              () => (window.location.href = "/criteria/my")
            );
          }}
        >
          <Form translate="yes">
            <Field name="id" type="hidden" />
            <div className="form-group">
              <label htmlFor="name">Criterion title</label>
              <Field name="name" className="form-control" type="text" />
            </div>
            <div className="form-group">
              <label htmlFor="interval">Interval</label>
              <Field
                name="interval"
                as="select"
                type="text"
                className="form-control"
                value={this.props.criterion.interval.toString()}
                title="interval"
              >
                <option value="0">week</option>
                <option value="1">month</option>
                <option value="2">quarter</option>
                <option value="3">half-year</option>
                <option value="4">year</option>
              </Field>
            </div>
            <div className="form-group">
              <label htmlFor="isDeleted">IsDeleted</label>
              <Field
                name="isDeleted"
                as="select"
                className="form-control"
                value={this.props.criterion.isDeleted.toString()}
                title="isDeleted"
              >
                <option value="false">no</option>
                <option value="true">yes</option>
              </Field>
            </div>
            <div className="form-group">
              <label htmlFor="groupId">Group</label>
              <Field
                name="groupId"
                as="select"
                type="number"
                className="form-control"
                value={this.props.criterion.groupId.toString()}
                title="group"
              >
                {this.props.groups.map((option) => (
                  <option key={option.id} value={option.id}>
                    {option.title}
                  </option>
                ))}
              </Field>
            </div>
            <div className="form-group">
              <label htmlFor="description">Description</label>
              <Field
                name="description"
                as="textarea"
                className="form-control"
              />
            </div>
            <button type="submit" className="btn btn-primary">
              Submit
            </button>
          </Form>
        </Formik>
      </React.Fragment>
    );
  }

因此,问题的关键在于我的选择值不是字符串,而是 html 规范将所有选择框视为具有文本值的元素。而且 fomik 有自己的restrictions

好的,我可以在选择后解析确切的类型(使用丑陋的'as any'),但我无法显示初始值:

当我指定 value={this.props.criterion.something.toString()} 时,我有一个渲染错误。我可以从 select 中更改另一个值,它会更改内部 formik 值(并正确发送到服务器端),但不会重新呈现视觉状态。

我可以删除value={this.props.criterion.something.toString()},所以我的初始值(我从api调用中检索它们,这就是我使用enableReinitialize的原因)无法正确显示。

官方文档包含带有文本选择框的示例,没有整数/布尔值。所以我无法理解处理类似问题的推荐方法,也许有人已经遇到过这个问题?也许,我走错了路,我需要更改我的代码(例如使用'onChange')?我尝试了不同类型的选择框(type="number"type="text"),但这并不影响。

【问题讨论】:

    标签: reactjs typescript formik


    【解决方案1】:

    您对不同的数据类型是正确的。由于此代码依赖于原生的HTMLSelectElement,因此事件值以字符串形式返回。

    因此,为了匹配您的数据类型,您必须将字符串值转换为数字。使用仅使用 id 和标签作为参考的选择框从集合中选择对象时也是如此。

    但是,您的实施存在一些问题。第一个问题是在使用Formik时,你总是想使用Formik的values。这个values 对象总是包含最后一个值。您现在使用的值与永远不会改变的 initialValues 相同。

    我认为以下更改应该可以使您的代码正常工作:

    1. &lt;Formik /&gt; 中删除enableReinitialize
    2. 为您的字段值使用 Formik 值而不是 this.props.criterion
    3. 序列化和反序列化来自 onChangevalue 属性中 Formik 值的 interval
    <Field
      as="select"
      name="interval"
      onChange={event => setFieldValue('interval', Number(event.target.value))}
      value={values.interval?.toString() || ''}
    >
      <option value="0">week</option>
      <option value="1">month</option>
      <option value="2">quarter</option>
    </Field>
    

    【讨论】:

      猜你喜欢
      • 2023-01-13
      • 2021-06-20
      • 1970-01-01
      • 2016-01-28
      • 2014-09-26
      • 1970-01-01
      • 2019-07-28
      • 2021-12-18
      • 2021-11-06
      相关资源
      最近更新 更多