带有打字稿的 formik 在 withFormik HOC 中设置了初始值
formik with typescript set initalvalue in withFormik HOC
我正在使用 typescript 添加 formik 并对我的项目做出反应,所以我将 withFormik 钩子用作 HOC,我面临的问题是我无法为响应设置初始值(在 hoc 中定义)我我来自 api
login.tsx
import { FormikProps } from "formik";
export interface FormValues {
title: string;
}
export const Login: React.FC<FormikProps<FormValues>> = (props) => {
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/todos/1")
.then((response) => response.json())
.then((json) => setTitle(json.title));
}, []);
const [title, setTitle] = useState<string | null>(null);
const { handleSubmit, handleBlur, handleChange, touched, errors, values } =
props;
return (
<Container component="main" maxWidth="xs">
<div className={classes.paper}>
<form className={classes.form} noValidate onSubmit={handleSubmit}>
<TextField
variant="outlined"
margin="normal"
required
fullWidth
id="title"
label="Title"
name="title"
value={values.title}
autoFocus
autoComplete="off"
onChange={handleChange}
onBlur={handleBlur}
/>
<Button
type="submit"
fullWidth
variant="contained"
color="primary"
className={classes.submit}
>
Sign In
</Button>
</form>
</div>
</Container>
);
};
login.hoc.tsx
import { Form, FormikProps, FormikValues, useFormik, withFormik } from "formik";
import { FormValues, Login } from "./index";
interface MyFormikProps {
}
export const LoginView = withFormik<MyFormikProps, FormValues>({
enableReinitialize: true,
mapPropsToValues: (props) => {
return { title:"" };
},
handleSubmit: (values) => {
console.log(values);
},
})(Login);
这工作得很好,但我的问题是假设我在 login.tsx 的 didmount 中点击了一个 api 然后你可以看到我设置了“标题”来响应我从api
现在我想将“标题”的初始值设置为我从 api
得到的响应
为什么你的 HOC 不起作用
您当前的设置可能无法工作,因为层次结构不正确。 withFormik
HOC 从组件的 props
创建初始值。但是 API 响应永远不会出现在 Login
的 props
中。它被保存到 Login
组件的 inside 状态。 外部 的 HOC 无法访问它。
您可以设置 withFormik
在 props
中获取正确的 API 数据,但您需要将 API 的提取提升到更高级别.
// component which renders the form, no more API fetch
export const Login: React.FC<FormikProps<FormValues>> = (props) => {/*...*/}
// data passed down from API
interface MyFormikProps {
title: string | null;
}
// component which sets up the form
export const LoginView = withFormik<MyFormikProps, FormValues>({
enableReinitialize: true,
mapPropsToValues: (props) => ({
title: props.title ?? "" // fallback if null
}),
handleSubmit: (values) => {
console.log(values);
}
})(Login);
// component which loads the data
export const ApiLoginForm = () => {
const [title, setTitle] = useState<string | null>(null);
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/todos/1")
.then((response) => response.json())
.then((json) => setTitle(json.title));
}, []);
return <LoginView title={title} />;
};
处理异步初始值
您 API 的价值需要时间来解决。将它用作 initial 值是很棘手的,因为一旦安装了窗体,初始值就必须存在。我们在这里所做的是回退到使用空字符串 ''
作为初始值。然后一旦 API 响应加载,表单将重置为新的初始值,因为您使用了 enableReinitialize
setting.
这将重置整个表单,如果 API 响应缓慢,可能会导致糟糕的用户体验。如果用户在响应返回之前在表单中输入文本,您不会希望覆盖用户输入。您可以禁用该字段,直到响应可用。或者您可以通过检查 touched.title
是否为 true
或 values.title
来使修改成为有条件的。如果您想更深入地了解如何修改表单,请继续阅读...
以编程方式修改 Formik 值
您可以使用 FormikProps
中的 setFieldValue
prop 强制修改字段的任何值。您可以通过调用 setFieldValue
.
来更改当前值,而不是更改初始值
这种方法更符合您当前的设置,因为它允许您将 API 调用保留在 Login
内。我们不需要本地 title
状态。您可以调用 setFieldValue
.
而不是使用已解析的响应调用 setTitle
export const Login: React.FC<FormikProps<FormValues>> = (props) => {
// access setFieldValue from props
const { setFieldValue, handleSubmit, handleBlur, handleChange, touched, errors, values } =
props;
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/todos/1")
.then((response) => response.json())
// could make this conditional, or add extra logic here
.then((json) => setFieldValue("title", json.title));
}, []);
return (
/* same JSX as before */
)
};
我正在使用 typescript 添加 formik 并对我的项目做出反应,所以我将 withFormik 钩子用作 HOC,我面临的问题是我无法为响应设置初始值(在 hoc 中定义)我我来自 api
login.tsx
import { FormikProps } from "formik";
export interface FormValues {
title: string;
}
export const Login: React.FC<FormikProps<FormValues>> = (props) => {
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/todos/1")
.then((response) => response.json())
.then((json) => setTitle(json.title));
}, []);
const [title, setTitle] = useState<string | null>(null);
const { handleSubmit, handleBlur, handleChange, touched, errors, values } =
props;
return (
<Container component="main" maxWidth="xs">
<div className={classes.paper}>
<form className={classes.form} noValidate onSubmit={handleSubmit}>
<TextField
variant="outlined"
margin="normal"
required
fullWidth
id="title"
label="Title"
name="title"
value={values.title}
autoFocus
autoComplete="off"
onChange={handleChange}
onBlur={handleBlur}
/>
<Button
type="submit"
fullWidth
variant="contained"
color="primary"
className={classes.submit}
>
Sign In
</Button>
</form>
</div>
</Container>
);
};
login.hoc.tsx
import { Form, FormikProps, FormikValues, useFormik, withFormik } from "formik";
import { FormValues, Login } from "./index";
interface MyFormikProps {
}
export const LoginView = withFormik<MyFormikProps, FormValues>({
enableReinitialize: true,
mapPropsToValues: (props) => {
return { title:"" };
},
handleSubmit: (values) => {
console.log(values);
},
})(Login);
这工作得很好,但我的问题是假设我在 login.tsx 的 didmount 中点击了一个 api 然后你可以看到我设置了“标题”来响应我从api
现在我想将“标题”的初始值设置为我从 api
得到的响应为什么你的 HOC 不起作用
您当前的设置可能无法工作,因为层次结构不正确。 withFormik
HOC 从组件的 props
创建初始值。但是 API 响应永远不会出现在 Login
的 props
中。它被保存到 Login
组件的 inside 状态。 外部 的 HOC 无法访问它。
您可以设置 withFormik
在 props
中获取正确的 API 数据,但您需要将 API 的提取提升到更高级别.
// component which renders the form, no more API fetch
export const Login: React.FC<FormikProps<FormValues>> = (props) => {/*...*/}
// data passed down from API
interface MyFormikProps {
title: string | null;
}
// component which sets up the form
export const LoginView = withFormik<MyFormikProps, FormValues>({
enableReinitialize: true,
mapPropsToValues: (props) => ({
title: props.title ?? "" // fallback if null
}),
handleSubmit: (values) => {
console.log(values);
}
})(Login);
// component which loads the data
export const ApiLoginForm = () => {
const [title, setTitle] = useState<string | null>(null);
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/todos/1")
.then((response) => response.json())
.then((json) => setTitle(json.title));
}, []);
return <LoginView title={title} />;
};
处理异步初始值
您 API 的价值需要时间来解决。将它用作 initial 值是很棘手的,因为一旦安装了窗体,初始值就必须存在。我们在这里所做的是回退到使用空字符串 ''
作为初始值。然后一旦 API 响应加载,表单将重置为新的初始值,因为您使用了 enableReinitialize
setting.
这将重置整个表单,如果 API 响应缓慢,可能会导致糟糕的用户体验。如果用户在响应返回之前在表单中输入文本,您不会希望覆盖用户输入。您可以禁用该字段,直到响应可用。或者您可以通过检查 touched.title
是否为 true
或 values.title
来使修改成为有条件的。如果您想更深入地了解如何修改表单,请继续阅读...
以编程方式修改 Formik 值
您可以使用 FormikProps
中的 setFieldValue
prop 强制修改字段的任何值。您可以通过调用 setFieldValue
.
这种方法更符合您当前的设置,因为它允许您将 API 调用保留在 Login
内。我们不需要本地 title
状态。您可以调用 setFieldValue
.
setTitle
export const Login: React.FC<FormikProps<FormValues>> = (props) => {
// access setFieldValue from props
const { setFieldValue, handleSubmit, handleBlur, handleChange, touched, errors, values } =
props;
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/todos/1")
.then((response) => response.json())
// could make this conditional, or add extra logic here
.then((json) => setFieldValue("title", json.title));
}, []);
return (
/* same JSX as before */
)
};