javascript - 如何使用 Formik 动态生成列表(例如通过 AJAX 或 setState)?

标签 javascript reactjs state formik

我有一个动态的表单字段数组,其值是通过 REST API 获取的。页面上还有一个下拉菜单,更改后会显示不同的字段数组。我在 componentDidMount 生命周期 Hook 期间获取所有这些字段/值,并过滤列表以显示相关数据。

福米克 docs mention FieldArrays作为处理字段数组的方法。然而,他们的示例显示了一个静态对象列表作为其 initialValues ——但我不知道如何动态生成列表。事实上,由于我通过 AJAX 获取 initialValues,它最初是一个空数组 - 因此即使在获取数据后也不会呈现任何内容。

这是我的代码的简化版本:

const MyComponent = class extends Component {    
    componentDidMount() {
        // data structure: [{Name: '', Id: '', Foo: '', Bar: ''}, ...]
        axios
        .get('/user')
        .then((res) => {
            this.setState({
                userData: res.data
            });
        });
    }



    render() {
        return (
            <div>
                <Formik
                    initialValues={{
                        users: this.state.userData
                    }}

                    render={({values}) => (
                        <Form>
                            <FieldArray
                                name="users"
                                render={arrayHelpers => (
                                    <ul>
                                        {
                                            values.users.map((user, index) => {
                                                return (
                                                    <li key={user.Id}>
                                                        <div>{user.Name}</div>
                                                        <Field  name={`user[${index}].Foo`} type="text" defaultValue={user.Foo}  />
                                                        <Field  name={`user[${index}].Bar`} type="text" defaultValue={user.Bar} />
                                                    </li>);
                                            }
                                        }
                                    </ul>
                                )}
                            />
                        </Form>
                    )}
                />
            </div>
        );
    }
}

最佳答案

您可以通过设置 enableReinitialize true 来执行此操作。根据文档,它将执行以下操作:

Default is false. Control whether Formik should reset the form if initialValues changes (using deep equality).

我创建了完整的codesanbox,其中您传入的数据是异步的,当您推送数据时它也是异步的。检查一下:

import React, { useEffect } from "react";
import ReactDOM from "react-dom";
import { Formik, Field, Form, ErrorMessage, FieldArray } from "formik";

const InviteFriends = () => {
  const [initialValues, setInitialValues] = React.useState({
    friends: []
  });

  useEffect(() => {
    const initialValues = {
      friends: [
        {
          name: "",
          email: ""
        }
      ]
    };
    const timer = setTimeout(() => {
      setInitialValues(initialValues);
    }, 1000);
    return () => {
      timer && clearTimeout(timer);
    };
  }, []);

  return (
    <div>
      <h1>Invite friends</h1>
      <Formik
        initialValues={initialValues}
        enableReinitialize={true}
        onSubmit={async (values) => {
          await new Promise((r) => setTimeout(r, 500));
          alert(JSON.stringify(values, null, 2));
        }}
      >
        {({ values }) => (
          <Form>
            <FieldArray name="friends">
              {({ insert, remove, push }) => (
                <div>
                  {console.log("Values", values, initialValues)}
                  {values.friends.length > 0 &&
                    values.friends.map((friend, index) => (
                      <div className="row" key={index}>
                        <div className="col">
                          <label htmlFor={`friends.${index}.name`}>Name</label>
                          <Field
                            name={`friends.${index}.name`}
                            placeholder="Jane Doe"
                            type="text"
                          />
                          <ErrorMessage
                            name={`friends.${index}.name`}
                            component="div"
                            className="field-error"
                          />
                        </div>
                        <div className="col">
                          <label htmlFor={`friends.${index}.email`}>
                            Email
                          </label>
                          <Field
                            name={`friends.${index}.email`}
                            placeholder="<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="fa909b949fba9b99979fd4999597" rel="noreferrer noopener nofollow">[email protected]</a>"
                            type="email"
                          />
                          <ErrorMessage
                            name={`friends.${index}.name`}
                            component="div"
                            className="field-error"
                          />
                        </div>
                        <div className="col">
                          <button
                            type="button"
                            className="secondary"
                            onClick={() => remove(index)}
                          >
                            X
                          </button>
                        </div>
                      </div>
                    ))}
                  <button
                    type="button"
                    className="secondary"
                    onClick={async () => {
                      await new Promise((r) =>
                        setTimeout(() => {
                          push({ name: "", email: "" });
                          r();
                        }, 500)
                      );
                    }}
                  >
                    Add Friend
                  </button>
                </div>
              )}
            </FieldArray>
            <button type="submit">Invite</button>
          </Form>
        )}
      </Formik>
    </div>
  );
};

ReactDOM.render(<InviteFriends />, document.getElementById("root"));



这是演示:https://codesandbox.io/s/react-formik-async-l2cc5?file=/index.js

关于javascript - 如何使用 Formik 动态生成列表(例如通过 AJAX 或 setState)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64674065/

相关文章:

javascript - Document.execCommand() 仅适用于开发人员工具

ios - React Native - NavigatorIOS

javascript - 未定义状态重选Js

reactjs - 为什么 this.state.count++ 在 this.setState({}) 中不起作用

javascript - 更新特定对象中的特定属性

javascript - 下一步 Auth "useSession"语法

javascript - 使用 Vivus.js 以所需方向动画线

javascript - 不可变 js 中 .toJS() 与 .toJSON() 哪个最好?

javascript - 从 WebSocket React 获取数据

animation - Flutter - 如何拥有任意数量的隐式动画