If you want to do it based on some kind of prop or state change, use the useEffect hook, e.g.,
useEffect(async ()=> {
const user = await userApi.get(props.id)
setUser(user)
}, [props.id]}
If you want to do so on a button click (or any event),
const handleClick = () => {
const user = await userApi.get(props.id)
setUser(user)
}
useCallback isn't really relied on for api calls or side-effects. useCallback is basically storing a "version" of a function, based on dependencies. When a dependency changes, you get a new function, because what it returns will be different, e.g.,
// props.id = 1
const doSomethingCallback = useCallback(() => {
/* do something with props.id */
}, [props.id])
While props.id === 1, doSomethingCallback will always reference the function as it was declared on the first render. If props.id changes to 2, useCallback will reference a new function. So, if doSomethingCallback was a dependency of a useEffect, when props.id changed to 2, useCallback would point to a new function, which would then get noticed by the useEffect and run whatever was in it, e.g.,
useEffect(() => { /* side-effect stuff */}, [doSomethingCallback])