reactjs - 使用 React 钩子重构功能组件
问题描述
我有几个共享相同逻辑的功能组件。所以我想用 React hooks 重构它们。他们都在挂载时向服务器发出一些调用,以检查订单是否已支付。如果是,paid
则 state 设置为 true ,并且正在下载文件。在提交时,我检查paid
状态是否设置为 true,如果是,则正在下载相同的文件,如果不是,则创建新订单并将用户重定向到带有付款表单的页面。
我已经提取了所有对服务器进行 API 调用的函数( getOrder()
、getPaymentState()
、createOrder()
和)。如何进一步优化此代码,以便我可以将、和移到组件之外,以便对其他组件也使用相同的逻辑?initPayment()
downloadFile()
checkOrder()
checkPayment()
downloadPDF()
newOrder()
这是我的组件:
const Form = () => {
const [paid, setPaid] = useState(false);
const [submitting, setSubmitting] = useState(false);
const [loading, setLoading] = useState(false);
const [data, setData] = useState({});
const checkOrder = async () => {
let search = new URLSearchParams(window.location.search);
let success = search.get("Success");
if (success) {
try {
const data = await getOrder();
setData(data);
checkPayment(data);
} catch (err) {
alert(err.message)
}
}
};
const checkPayment = async values => {
try {
const paid = await getPaymentState();
setPaid(paid);
downloadPDF(values);
} catch (err) {
alert(err.message)
}
};
const downloadPDF = async values => {
setLoading(true);
let downloadData = {
email: values.email,
phone: values.phone
}
const response = await downloadFile(downloadData, sendURL);
setLoading(false);
window.location.assign(response.pdf);
}
const newOrder = async values => {
setSubmitting(true);
const order = await createOrder(values, description, sum);
const paymentUrl = await initPayment(order, description, sum, returnURL);
setSubmitting(false);
window.location.assign(paymentUrl);
}
const onSubmit = async values => {
if (paid) {
try {
downloadPDF(data);
} catch (err) {
console.log(err);
}
} else {
try {
newOrder(values)
} catch (err) {
alert(err.message)
}
}
};
useEffect(() => {
checkOrder();
}, []);
return (
)
}
编辑 1:我还需要能够将一些数据传递给这个钩子:downloadData
、sendURL
、和description
,这在每种情况下都会有所不同。然后需要填充来自.sum
returnURL
downloadData
values
如果您能指出正确的方向,我将不胜感激。我只是在学习 React,我真的很想找到正确的方法来做到这一点。
编辑2:我已经根据以前的答案发布了我自己的答案和工作代码。这不是最终的,因为我仍然需要移出downloadPDF()
组件并传递downloadData
给它,但是当我这样做时,我收到一个错误,即值未定义。如果有人可以帮助我,我会接受它作为答案。
解决方案
您可以将 Form 组件中的所有通用内容提取到自定义 Hook 中,并从此挂钩返回所需的值
依赖项的值会根据被调用的组件而变化,可以作为参数传递给钩子。该钩子还可以返回一个 onSubmit 函数,您可以将 downloadData 传递给该函数
const useOrderHook = ({returnURL, sendURL, }) => {
const [paid, setPaid] = useState(false);
const [submitting, setSubmitting] = useState(false);
const [loading, setLoading] = useState(false);
const [data, setData] = useState({});
const checkOrder = async () => {
let search = new URLSearchParams(window.location.search);
let success = search.get("Success");
if (success) {
try {
const data = await getOrder();
setData(data);
checkPayment(data);
} catch (err) {
alert(err.message)
}
}
};
const checkPayment = async values => {
try {
const paid = await getPaymentState();
setPaid(paid);
downloadPDF(values);
} catch (err) {
alert(err.message)
}
};
const downloadPDF = async values => {
setLoading(true);
let downloadData = {
email: values.email,
phone: values.phone
}
const response = await downloadFile(downloadData, sendURL);
setLoading(false);
window.location.assign(response.pdf);
}
const newOrder = async (values, description, sum) => {
setSubmitting(true);
const order = await createOrder(values, description, sum);
const paymentUrl = await initPayment(order, description, sum, returnURL);
setSubmitting(false);
window.location.assign(paymentUrl);
}
const onSubmit = async ({values, downloadData: data, description, sum}) => {
if (paid) {
try {
downloadPDF(data);
} catch (err) {
console.log(err);
}
} else {
try {
newOrder(values, description, sum)
} catch (err) {
alert(err.message)
}
}
};
useEffect(() => {
checkOrder();
}, []);
return {onSubmit, loading, submitting, paid, data };
}
现在您可以在像 Form 这样的组件中使用这个钩子,如下所示
const Form = () => {
const {onSubmit, newOrder, loading, submitting, paid, data } = useOrderHook({returnUrl: 'someUrl', sendURL: 'Some send URL'})
const handleSubmit = (values) => {
// since this function is called, you can get the values from its closure.
const data = {email: values.email, phone: values.phone}
onSubmit({ data, values, description, sum})// pass in the required values for onSubmit here. you can do the same when you actually call newOrder from somewhere
}
// this is how you pass on handleSubmit to React-final-form
return <Form
onSubmit={handleSubmit }
render={({ handleSubmit }) => {
return <form onSubmit={handleSubmit}>...fields go here...</form>
}}
/>
}
推荐阅读
- reactjs - PWA - 在 IOS 上将页面添加到主屏幕会阻止访问摄像头
- sql - 在sql查询中获取最小开始时间和最大结束时间
- erlang - 查找元组列表中的所有元组
- selector - Puppeteer waitForSelector('selector') 是否仅适用于字符串而不适用于 page.$('selector')?
- c++ - boost::spirit::qi 保留空白
- javascript - 如何在将 Formik 中的值发送到 Firebase 之前正确修改它们?
- r - 在 R 中模拟泊松过程
- javascript - 在 typescript/javascript 的 google.maps.Geocoder().geocode() 上使用全局变量
- javascript - Angularr:如何使用 Angular 路由器传递数据
- angular - Firebase:数据更改时获取新集合