尝试使用 Formik 重构 onSubmit 属性
Posted
技术标签:
【中文标题】尝试使用 Formik 重构 onSubmit 属性【英文标题】:Trying to refactor the onSubmit property using Formik 【发布时间】:2021-01-19 05:30:44 【问题描述】:使用 React 提升我的开发技能。我试图想办法重构 onSubmit 属性。我的应用程序是一个使用 Formik 组件的联系表单,它将数据发送到 Firebase Cloudstore 并通过 emailjs 发送电子邮件。如果成功,它将使用 Material UI 的 Snackbar 弹出一个弹出窗口。它有效,但只是试图清理代码。请帮忙!
onSubmit=(values, resetForm, setSubmitting ) =>
emailjs.send("blah","blah",
email: values.email,
name: values.name,
message: values.message
,
'blah',);
//this is sent to firebase cloudstore
db.collection("contactForm")
.add(
name: values.name,
email: values.email,
message: values.message,
)
.then(() =>
handleClick();
)
.catch((error) =>
alert(error.message);
);
setTimeout(() =>
resetForm();
setSubmitting(false);
/* console.log(values);
console.log(JSON.stringify(values, null, 2)); */
, 500);
这是完整的功能
function Contact()
const [open, setOpen] = React.useState(false);
const handleClose = (event, reason) =>
if (reason === "clickaway")
return;
setOpen(false);
;
const handleClick = () =>
setOpen(true);
;
const classes = useStyles();
return (
<Formik
initialValues=initialValues
validationSchema=validationSchema
onSubmit=(values, resetForm, setSubmitting ) =>
emailjs.send("blah","blah",
email: values.email,
name: values.name,
message: values.message
,
'blah',);
//this is sent to firebase cloudstore
db.collection("contactForm")
.add(
name: values.name,
email: values.email,
message: values.message,
)
.then(() =>
handleClick();
)
.catch((error) =>
alert(error.message);
);
setTimeout(() =>
resetForm();
setSubmitting(false);
/* console.log(values);
console.log(JSON.stringify(values, null, 2)); */
, 500);
>
( submitForm, isSubmitting ) => (
<Form>
<Snackbar open=open autoHideDuration=6000 onClose=handleClose>
<Alert onClose=handleClose severity="success">
Your message has been sent!
</Alert>
</Snackbar>
<div>
<Field
component=TextField
label="Name"
name="name"
type="name"
/>
<ErrorMessage name="name" />
</div>
<div>
<Field
component=TextField
label="Your email"
name="email"
type="email"
/>
<ErrorMessage name="email" />
</div>
<br />
<br />
<div>
<Field
as="textarea"
placeholder="Your Message"
label="message"
name="message"
type="message"
rows="15"
cols="70"
/>
<ErrorMessage name="message" />
</div>
isSubmitting && <LinearProgress />
<Button
variant="contained"
color="primary"
disabled=isSubmitting
onClick=submitForm
>
Submit
</Button>
</Form>
)
</Formik>
);
【问题讨论】:
【参考方案1】:我建议在组件主体中将 onSubmit 属性设为它自己的函数,您需要使用 useCallback 来记忆它。此外,您可以创建一个挂钩来控制警报组件,您还可以允许挂钩来控制天气是错误还是成功类型,从而减少在保存失败时重复代码的需要。
您的提交处理程序可能如下所示,请注意我省略了电子邮件的发送并模拟了 firebase 部分。您也可以在 promise 上调用 finally,而不是在 then
和 catch
块中调用 setSubmitting。
const handleSubmit = React.useCallback(
(values, setSubmitting, resetForm ) =>
db.collection("contact")
.add(values)
.then((res) =>
show( message: "Your message has been sent" );
)
.catch((err) =>
show( variant: "error", message: "Failed to send your message." );
)
.finally(() =>
setSubmitting(false);
);
,
[show]
);
上面示例中的 show 函数将成为控制警报的钩子的一部分。钩子可能看起来像这样,它可以根据您的用例进行扩展。
import React from "react";
const useAlert = () =>
const [state, setState] = React.useState(
variant: "success",
visibile: false,
message: null
);
const show = React.useCallback(
(options = ) =>
setState((prev) => (
...prev,
...options,
visible: true
));
,
[setState]
);
const hide = React.useCallback(() =>
setState((prev) => ( ...prev, visibile: false ));
, [setState]);
return ...state, show, hide ;
;
export default useAlert;
此外,由于您使用的是材质 ui,因此您需要利用它们的内置组件。这将消除您对多个 <br />
s 间距的需要,并有助于保持 UI 一致。
<Box marginBottom=1>
<Field component=TextField label="Name" name="name" type="name" />
<ErrorMessage name="name" />
</Box>
<Box marginBottom=1>
<Field
component=TextField
label="Email"
name="email"
type="email"
/>
<ErrorMessage name="email" />
</Box>
此外,您可以将内置组件用于文本区域,以保持设计一致。使用multiline prop 允许您将输入设为文本区域。
<Box marginBottom=2>
<Field
component=TextField
placeholder="Your Message"
label="Message"
name="message"
type="message"
rows=5
multiline
fullWidth
/>
<ErrorMessage name="message" />
</Box>
我个人不太喜欢以您的方式使用 LinearProgress。我个人认为循环过程看起来更好,特别是在提交按钮内使用时。 Here are the relevant docs.
<Button
variant="contained"
color="primary"
disabled=isSubmitting
onClick=submitForm
endIcon=isSubmitting && <CircularProgress size=15 />
>
Submit
</Button>
I've put a working example together in a codesandbox.
【讨论】:
哇!感谢您的努力,还有更多。我可以使用您提供的内容来清理我的代码中的许多其他内容....谢谢! 对于其他人,useCallback 有开销,仅在必要时使用。 @BluePie 你有那个来源吗?我认为与使用 useCallback 相关的成本低于在每次渲染上分配新函数的成本。以上是关于尝试使用 Formik 重构 onSubmit 属性的主要内容,如果未能解决你的问题,请参考以下文章