我有一个动态的表单字段数组,其值是通过 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/