[英]useCallback with updated state object - React.js
I have a POST
API call that I make on a button click.我有一个
POST
API 调用,我在单击按钮时进行了调用。 We have one large state object that gets sent as body
for a POST
call.我们有一个大型状态对象,它作为
POST
调用的body
发送。 This state object keeps getting updated based on different user interactions on the page.这个状态对象会根据页面上不同的用户交互不断更新。
function QuotePreview(props) {
const [quoteDetails, setQuoteDetails] = useState({});
const [loadingCreateQuote, setLoadingCreateQuote] = useState(false);
useEffect(() => {
if(apiResponse?.content?.quotePreview?.quoteDetails) {
setQuoteDetails(apiResponse?.content?.quotePreview?.quoteDetails);
}
}, [apiResponse]);
const onGridUpdate = (data) => {
let subTotal = data.reduce((subTotal, {extendedPrice}) => subTotal + extendedPrice, 0);
subTotal = Math.round((subTotal + Number.EPSILON) * 100) / 100
setQuoteDetails((previousQuoteDetails) => ({
...previousQuoteDetails,
subTotal: subTotal,
Currency: currencySymbol,
items: data,
}));
};
const createQuote = async () => {
try {
setLoadingCreateQuote(true);
const result = await usPost(componentProp.quickQuoteEndpoint, quoteDetails);
if (result.data?.content) {
/** TODO: next steps with quoteId & confirmationId */
console.log(result.data.content);
}
return result.data;
} catch( error ) {
return error;
} finally {
setLoadingCreateQuote(false);
}
};
const handleQuickQuote = useCallback(createQuote, [quoteDetails, loadingCreateQuote]);
const handleQuickQuoteWithoutDeals = (e) => {
e.preventDefault();
// remove deal if present
if (quoteDetails.hasOwnProperty("deal")) {
delete quoteDetails.deal;
}
handleQuickQuote();
}
const generalInfoChange = (generalInformation) =>{
setQuoteDetails((previousQuoteDetails) => (
{
...previousQuoteDetails,
tier: generalInformation.tier,
}
));
}
const endUserInfoChange = (endUserlInformation) =>{
setQuoteDetails((previousQuoteDetails) => (
{
...previousQuoteDetails,
endUser: endUserlInformation,
}
));
}
return (
<div className="cmp-quote-preview">
{/* child components [handleQuickQuote will be passed down] */}
</div>
);
}
when the handleQuickQuoteWithoutDeals
function gets called, I am deleting a key from the object.当
handleQuickQuoteWithoutDeals
函数被调用时,我正在从对象中删除一个键。 But I would like to immediately call the API with the updated object.但我想立即使用更新后的对象调用 API。 I am deleting the deal key directly here, but if I do it in an immutable way, the following API call is not considering the updated object but the previous one.
我在这里直接删除交易键,但是如果我以不可变的方式执行此操作,则以下 API 调用不会考虑更新的对象,而是考虑前一个。
The only way I found around this was to introduce a new state and update it on click and then make use of the useEffect
hook to track this state to make the API call when it changes.我发现解决此问题的唯一方法是引入一个新状态并在单击时更新它,然后使用
useEffect
钩子跟踪此状态以在它更改时进行 API 调用。 With this approach, it works in a weird way where it keeps calling the API on initial load as well and other weird behavior.使用这种方法,它以一种奇怪的方式工作,它在初始加载时不断调用 API 以及其他奇怪的行为。
Is there a cleaner way to do this?有没有更干净的方法来做到这一点?
It's not clear how any children would call the handleQuickQuote
callback, but if you are needing to close over in callback scope a "copy" of the quoteDetails
details then I suggest the following small refactor to allow this parent component to use the raw createQuote
function while children receive a memoized callback with the current quoteDetails
enclosed.目前尚不清楚任何子级将如何调用
handleQuickQuote
回调,但是如果您需要在回调范围内关闭quoteDetails
详细信息的“副本”,那么我建议进行以下小重构以允许此父组件在同时使用原始createQuote
函数孩子们收到一个带有当前quoteDetails
的记忆回调。
Consume quoteDetails
as an argument:使用
quoteDetails
作为参数:
const createQuote = async (quoteDetails) => {
try {
setLoadingCreateQuote(true);
const result = await usPost(componentProp.quickQuoteEndpoint, quoteDetails);
if (result.data?.content) {
/** TODO: next steps with quoteId & confirmationId */
console.log(result.data.content);
}
return result.data;
} catch( error ) {
return error;
} finally {
setLoadingCreateQuote(false);
}
};
Memoize an "anonymous" callback that passes in the quoteDetails
value:记住传入
quoteDetails
值的“匿名”回调:
const handleQuickQuote = useCallback(
() => createQuote(quoteDetails),
[quoteDetails]
);
Create a shallow copy of quoteDetails
, delete the property, and call createQuote
:创建一个
quoteDetails
的浅拷贝,删除该属性,然后调用createQuote
:
const handleQuickQuoteWithoutDeals = (e) => {
e.preventDefault();
const quoteDetailsCopy = { ...quoteDetails };
// remove deal if present
if (quoteDetailsCopy.hasOwnProperty("deal")) {
delete quoteDetailsCopy.deal;
}
createQuote(quoteDetailsCopy);
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.