I'm trying to fetch data from Spotify API. Since I need an access token to do this, I built a custom hook to parse the token from the URL that comes from the server.
I also have another custom hook with the actual request to the API that takes the parsed token as an argument. Both are gathered in a parent hook.
I cannot make this work since the token is never reaching the scope of the request hook so it fails. If I parse the token and make the request within the same hook everything works out just fine. I intended to make a hook for every request since it's not just one, that's why I wanted to pass the token as an argument.
Token custom hook
export default () => {
const [ token, setToken ] = useState('')
useEffect(() => {
const { access_token } = queryString.parse(window.location.search)
return setToken(access_token)
}, [])
return token
}
Request hook
export default function useFetchUserData(token) {
//state
const initialUserState = {
display_name: '',
external_url: '',
images: ''
}
const [ userData, setUserData ] = useState(initialUserState)
const [ isLoading, setIsLoading ] = useState(false)
const [ isError, setIsError ] = useState(false)
useEffect(() => {
async function getUserData() {
setIsLoading(true);
setIsError(false);
const spotify = axios.create({
baseURL: 'https://api.spotify.com/v1/me',
headers: {
'Authorization': `Bearer ${token}`
}
})
try {
const userRes = await spotify('/')
.then( res => { return res.data });
setUserData({
display_name: userRes.display_name,
external_url: userRes.external_urls.spotify,
images: userRes.images[0].url
})
} catch (error) {
setIsError(true)
}
setIsLoading(false);
}
getUserData();
}, [])
const data = {
userData,
isLoading,
isError
}
return data
}
Parent hook
export default function Home() {
const token = useParseToken()
const { userData, isLoading, isError } = useFetchUserData(token);
if (isLoading) return <BarLoader />;
if (isError) return <div>Oops! something went wrong</div>;
return (
<Fragment>
<Header userData={userData}/>
</Fragment>
)
}
You have to use createContext api of react. Save your token as a context. and use it where ever you want. I think this repository will help you.
What happens in your case is that you are setting a state in useEffect
hook in your custom hook to set token. However you return the token from this hook without waiting for the effect to run, so the first time your useFetchUserData
hook is called, it will receive empty string as a token. To solve this, you must implement the useFetchUserData
hook to run once token is available or it changed
export default function useFetchUserData(token) {
//state
const initialUserState = {
display_name: '',
external_url: '',
images: ''
}
const [ userData, setUserData ] = useState(initialUserState)
const [ isLoading, setIsLoading ] = useState(false)
const [ isError, setIsError ] = useState(false)
useEffect(() => {
async function getUserData() {
setIsLoading(true);
setIsError(false);
const spotify = axios.create({
baseURL: 'https://api.spotify.com/v1/me',
headers: {
'Authorization': `Bearer ${token}`
}
})
try {
const userRes = await spotify('/')
.then( res => { return res.data });
setUserData({
display_name: userRes.display_name,
external_url: userRes.external_urls.spotify,
images: userRes.images[0].url
})
} catch (error) {
setIsError(true)
}
setIsLoading(false);
}
if(token !== '' || token !== null) {
getUserData();
}
}, [token])
const data = {
userData,
isLoading,
isError
}
return data
}
Also since useParseToken
returns the token, you don't need to destructure it while using
const token = useParseToken();
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.