如何在两个自定义挂钩之间共享状态?
How can I share state between two custom hooks?
我正在尝试从 Spotify API 获取数据。由于我需要一个访问令牌来执行此操作,因此我构建了一个自定义挂钩来解析来自服务器的 URL 中的令牌。
我还有另一个自定义挂钩,其中包含对 API 的实际请求,该挂钩将已解析的令牌作为参数。两者都聚集在父挂钩中。
我无法完成这项工作,因为令牌永远不会到达请求挂钩的范围,所以失败了。如果我解析令牌并在同一个挂钩中发出请求,一切都会正常进行。我打算为每个请求制作一个钩子,因为它不仅仅是一个,这就是为什么我想将令牌作为参数传递的原因。
令牌自定义挂钩
export default () => {
const [ token, setToken ] = useState('')
useEffect(() => {
const { access_token } = queryString.parse(window.location.search)
return setToken(access_token)
}, [])
return token
}
请求挂钩
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
}
父挂钩
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>
)
}
你必须使用 react 的 createContext api。
将您的令牌保存为上下文。随时随地使用它。
我想 this repository 会对你有所帮助。
您的情况是您在自定义挂钩中的 useEffect
挂钩中设置状态以设置令牌。但是,您 return 来自此挂钩的标记无需等待 运行 的效果,因此第一次调用 useFetchUserData
挂钩时,它将接收空字符串作为标记。要解决此问题,您必须在令牌可用或更改后 useFetchUserData
挂钩 运行
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
}
此外,由于 useParseToken
return 是令牌,因此在使用
时无需解构它
const token = useParseToken();
我正在尝试从 Spotify API 获取数据。由于我需要一个访问令牌来执行此操作,因此我构建了一个自定义挂钩来解析来自服务器的 URL 中的令牌。
我还有另一个自定义挂钩,其中包含对 API 的实际请求,该挂钩将已解析的令牌作为参数。两者都聚集在父挂钩中。
我无法完成这项工作,因为令牌永远不会到达请求挂钩的范围,所以失败了。如果我解析令牌并在同一个挂钩中发出请求,一切都会正常进行。我打算为每个请求制作一个钩子,因为它不仅仅是一个,这就是为什么我想将令牌作为参数传递的原因。
令牌自定义挂钩
export default () => {
const [ token, setToken ] = useState('')
useEffect(() => {
const { access_token } = queryString.parse(window.location.search)
return setToken(access_token)
}, [])
return token
}
请求挂钩
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
}
父挂钩
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>
)
}
你必须使用 react 的 createContext api。 将您的令牌保存为上下文。随时随地使用它。 我想 this repository 会对你有所帮助。
您的情况是您在自定义挂钩中的 useEffect
挂钩中设置状态以设置令牌。但是,您 return 来自此挂钩的标记无需等待 运行 的效果,因此第一次调用 useFetchUserData
挂钩时,它将接收空字符串作为标记。要解决此问题,您必须在令牌可用或更改后 useFetchUserData
挂钩 运行
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
}
此外,由于 useParseToken
return 是令牌,因此在使用
const token = useParseToken();