具有更新状态对象的 useCallback - React.js
useCallback with updated state object - React.js
我有一个 POST
API 调用,我在单击按钮时进行调用。我们有一个大型状态对象,它作为 body
发送给 POST
调用。此状态对象会根据页面上的不同用户交互不断更新。
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>
);
}
当 handleQuickQuoteWithoutDeals
函数被调用时,我正在从对象中删除一个键。但我想立即用更新后的对象调用 API 。我在这里直接删除交易密钥,但如果我以不可变的方式进行删除,则以下 API 调用不会考虑更新的对象,而是考虑前一个对象。
我发现解决这个问题的唯一方法是引入一个新状态并在点击时更新它,然后利用 useEffect
挂钩来跟踪这个状态,以便在它出现时进行 API 调用变化。使用这种方法,它会以一种奇怪的方式工作,它会在初始加载时不断调用 API 以及其他奇怪的行为。
有更简洁的方法吗?
不清楚 children 将如何调用 handleQuickQuote
回调,但如果您需要在回调范围内关闭 quoteDetails
详细信息的“副本”,那么我建议进行以下小重构,以允许此 parent 组件使用原始 createQuote
函数,而 children 接收包含当前 quoteDetails
的记忆回调。
使用 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);
}
};
记住传入 quoteDetails
值的“匿名”回调:
const handleQuickQuote = useCallback(
() => createQuote(quoteDetails),
[quoteDetails]
);
创建 quoteDetails
的浅表副本,删除 属性,然后调用 createQuote
:
const handleQuickQuoteWithoutDeals = (e) => {
e.preventDefault();
const quoteDetailsCopy = { ...quoteDetails };
// remove deal if present
if (quoteDetailsCopy.hasOwnProperty("deal")) {
delete quoteDetailsCopy.deal;
}
createQuote(quoteDetailsCopy);
}
我有一个 POST
API 调用,我在单击按钮时进行调用。我们有一个大型状态对象,它作为 body
发送给 POST
调用。此状态对象会根据页面上的不同用户交互不断更新。
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>
);
}
当 handleQuickQuoteWithoutDeals
函数被调用时,我正在从对象中删除一个键。但我想立即用更新后的对象调用 API 。我在这里直接删除交易密钥,但如果我以不可变的方式进行删除,则以下 API 调用不会考虑更新的对象,而是考虑前一个对象。
我发现解决这个问题的唯一方法是引入一个新状态并在点击时更新它,然后利用 useEffect
挂钩来跟踪这个状态,以便在它出现时进行 API 调用变化。使用这种方法,它会以一种奇怪的方式工作,它会在初始加载时不断调用 API 以及其他奇怪的行为。
有更简洁的方法吗?
不清楚 children 将如何调用 handleQuickQuote
回调,但如果您需要在回调范围内关闭 quoteDetails
详细信息的“副本”,那么我建议进行以下小重构,以允许此 parent 组件使用原始 createQuote
函数,而 children 接收包含当前 quoteDetails
的记忆回调。
使用 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);
}
};
记住传入 quoteDetails
值的“匿名”回调:
const handleQuickQuote = useCallback(
() => createQuote(quoteDetails),
[quoteDetails]
);
创建 quoteDetails
的浅表副本,删除 属性,然后调用 createQuote
:
const handleQuickQuoteWithoutDeals = (e) => {
e.preventDefault();
const quoteDetailsCopy = { ...quoteDetails };
// remove deal if present
if (quoteDetailsCopy.hasOwnProperty("deal")) {
delete quoteDetailsCopy.deal;
}
createQuote(quoteDetailsCopy);
}