尝试使用 Formik 重构 onSubmit 属性
Trying to refactor the onSubmit property using Formik
用 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>
);
}
我建议让 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;
此外,由于您正在使用 material ui,因此您需要在组件中利用它们的 built。这将消除对多个 <br />
间距的需要,并有助于保持 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>
此外,您可以将 built in 组件用于文本区域,以保持设计的一致性。使用 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>
用 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>
);
}
我建议让 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;
此外,由于您正在使用 material ui,因此您需要在组件中利用它们的 built。这将消除对多个 <br />
间距的需要,并有助于保持 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>
此外,您可以将 built in 组件用于文本区域,以保持设计的一致性。使用 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>