How to conditionally fetch user data based on logged-in state with SWR?
I am trying to set some UI state that is dependent on if a user is logged in. If a user is logged in, some state in the UI should reflect this.
I am using SSG to statically generate pages and SWR to fetch the user data. When I call my fetcher function and try to call my custom hook to check if the user is logged in, on the initial request, the user is undefined, but when I reload, the user is present.
Why is this the case? Is the fetcher function called before anything else and how can I fix this.
Basically, all I want is to SSG the [parkCode].js
pages and fetch some user data to display user specific state.
Here is my code:
// [parkCode].js
import checkUser from '../../hooks/checkUser'
import useSWR from 'swr'
export default function Park({parkCode})
const user = checkUser()
const fetcher = async () => {
const username = await user?.username
console.log(username)
try {
const {data} = await API.graphql({
query: listSites,
variables: {
filter: {
code: {eq: parkCode},
owner: {eq: username},
},
},
})
return data?.listSites?.items[0] || null
} catch (err) {
console.error('Site not added by user', err)
}
}
const {data, error} = useSWR('park', fetcher)
console.log(data) // logs an error (says
}
My hook to see if a user is logged in
//checkUser.js
import {useState, useEffect} from 'react'
import {Auth, Hub} from 'aws-amplify'
export default function checkUser() {
const [user, setUser] = useState(null)
useEffect(() => {
checkUserAuth()
const unsubscribe = Hub.listen('auth', () => checkUserAuth())
return () => unsubscribe()
}, [])
async function checkUserAuth() {
try {
const signedInUser = await Auth.currentAuthenticatedUser()
setUser(signedInUser)
} catch (err) {
setUser(null)
}
}
return user
}
When the page is first rendered, the user
variable still has its initial state (null
), as the checkUser
hook useEffect
hasn't run yet. This means that when useSWR('park', fetcher)
is called, the user
inside the fetcher method will also be null
. To prevent this behaviour, you can conditionally fetch the data in the useSWR
call only when the user
is set.
export default function Park({ parkCode })
const user = checkUser()
const fetcher = async () => {
// No need to call `await` to get `username` here
const username = user?.username
try {
const { data } = await API.graphql({
query: listSites,
variables: {
filter: {
code: { eq: parkCode },
owner: { eq: username },
}
}
})
return data?.listSites?.items[0] || null
} catch (err) {
console.error('Site not added by user', err)
}
}
// Only call the fetcher method if `user` exists
const { data, error } = useSWR(user ? ['park', user?.username] : null, fetcher)
if (data) {
// Handle `data` when it's set
}
// Rest of your component
}