Reputation: 1024
I've build an custom custom post hook that returns the API response and the API post. And I am using useCallback
hook to set the Response state
Where it goes wrong is that the Package prop
doesn't update inside the useCallback
hook.
When I log Package
outside the useCallback
hook I get the right data inside the propertie. However when I log the Package prop
inside the useCallback
hook the value of Package
doesn't change.
No matter how many times I press the button
I've tried creating an order state
that updates everytime the Package prop
updates, however whenever I set Package
as an value in the scope
I get an infinite loop.
I've alos added Package
into the scope
of the useCallback
hook
example
React.useEffect(() => {
setOrder(Package);
}, [Package]);
What I expect to happen is that whenever I call my custom usePostOrder
hook the value of Package
that is inside the useCallback
is always up to date with the latest passed on prop.
CustomHook
/**
* custom post hook that returns the API response and the API post function
* @param {string} url
* @param {object} Package
* @returns {array} and @param {function}
*/
export const usePostOrder = (url, Package) => {
const [loading, setLoading] = React.useState(true);
const [order, setOrder] = React.useState(Package);
const [response, setResponse] = React.useState({
config: {
data: []
},
data: {
id: 0
}
});
console.log("outside func", Package);
const postOrder = React.useCallback(async () => {
console.log("inside func", Package);
}, [url, loading, Package]);
return [response, postOrder];
};
Answer by Jake Luby with a slight adjustment
/**
* custom post hook that returns the API response and the API post function
* @param {string} url
* @param {object} Package
* @returns {array} and @param {function}
*/
export const usePostOrder = (url, Package, send) => {
const [postOrder, setPostOrder] = React.useState();
const [response, setResponse] = React.useState({
config: {
data: []
},
data: {
id: 0
}
});
React.useEffect(() => {
const getData = async send => {
//this will have the updated input Package
await axios
.post(ApiUrl + url, Package)
.then(function(response) {
setResponse(response);
})
.catch(function(error) {
setResponse(error);
console.log(error);
});
};
send && getData();
}, [send]); //this will run when url or Package changes
return [response, postOrder];
};
useAsyncEndpoint.PropTypes = {
url: PropTypes.url,
user: PropTypes.object,
club: PropTypes.object,
cartItems: PropTypes.array
};
How I call this hook
import {usePostOrder} from "./yourHooksFolder"
const [send, setSend] = React.useState(false);
const [response, postOrder] = usePostOrder(
"url",
createOrder(user, store, cartItems),
send
);
React.useEffect(() => {
setSend(false);
}, [response]);
// send order
const onGoToPaymentPressed = () => {
setSend(true);
};
Upvotes: 8
Views: 9602
Reputation: 1758
useCallback
is not meant to be used like that. It doesn't actually run the function, it simply memoizes it so that between renders the same function isn't recreated.
What you want is the useEffect
hook and to have the postOrder as part of the state:
export const usePostOrder = (url, Package) => {
const [postOrder, setPostOrder] = React.useState()
const [response, setResponse] = React.useState({
config: {
data: []
},
data: {
id: 0
}
})
React.useEffect(() => {
const getData = async url => {
//this will have the updated input Package
console.log(Package)
//here is where you'll have your REST calls
//set your data which will then update the return values in the hook and cause a rerender
setPostOrder(returnValue)
setResponse(someResponse)
}
getData()
}, [url, Package]) //this will run when url or Package changes
return [response, postOrder]
}
Upvotes: 7