I have a rather basic use-case: I want to get the user info from the server when the app loads and then using a hook to get the info in different components.
For some reason, I run into an infinite loop and get Error: Maximum update depth exceeded.
getMe
gets called recursively until the app crashes. Is that a correct hook behavior?
This is the relevant part of the hook:
export default function useUser () {
const [user, setUser] = useState(null)
const [authenticating, setAuthenticating] = useState(true)
// ...
const getMe = (jwt) => {
console.log('set user')
axios.get(baseURL + endpoints.currentUser, { headers: {
'X-Access-Token': jwt,
'Content-Type': 'application/json'
}}).then(response => {
setUser({
name: response.data.name,
img: response.data.avatar_url
})
})
}
useEffect(() => {
getMe(jwt)
}, [])
return { user, authenticating }
}
This is the first call
function App () {
const { user, authenticating } = useUser()
const c = useStyles()
return (
authenticating ? (
<div className={c.wrapper}>
<Loader size={60}/>
</div>
) : (
<div className={c.wrapper}>
<div className={c.sidebar}>
<img className={c.lamp} src={ user ? user.img : lamp } />
And I also call need the user in the Router component
const Routes = () => {
const { user } = useUser()
return (
<Router history={history}>
<Switch>
// ...
<Route
path={pages.login}
render={routeProps => (
user ?
<Redirect to={pages.main}/> :
<Login {...routeProps}/>
)}
/>
You shouldn't be requesting the server each time you call the hook since it pretty much unnecessary. You could use Redux or context for this (for this paradigm redux would be better). However, if you insist on this method, it seems you have to wrap your getMe
function in a useCallback
hook since it must be re-rendering each time the function runs.
Read more on the useCallback
hook:
You're now making a request via the useEffect
in your custom hook - why not let the component do that programatically?
Change getMe
to a useCallback
function and export it:
export default function useUser () {
const [user, setUser] = useState(null)
const [authenticating, setAuthenticating] = useState(true)
// ...
const getMe = useCallback((jwt) => {
console.log('set user')
axios.get(baseURL + endpoints.currentUser, { headers: {
'X-Access-Token': jwt,
'Content-Type': 'application/json'
}}).then(response => {
setUser({
name: response.data.name,
img: response.data.avatar_url
})
})
}, [])
return { user, authenticating, doFetch: getMe }
}
..and use that function in your components (import doFetch
and call it on mount), eg:
function App () {
const { user, authenticating, doFetch } = useUser()
const c = useStyles()
useEffect(() => doFetch(), [doFetch])
return (
authenticating ? (
<div className={c.wrapper}>
<Loader size={60}/>
</div>
) : (
<div className={c.wrapper}>
<div className={c.sidebar}>
<img className={c.lamp} src={ user ? user.img : lamp } />
You now avoid the infinite loop and your component takes control of the request logic instead of the reusable hook.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.