我使用短期JWT令牌访问我的API;令牌需要每10分钟左右提取一次。我的根App
组件每隔一段时间获取令牌,将其设置为本地状态并传递到所有组件都可以访问的上下文中。
function App() {
const queryClient = new QueryClient()
const [auth, setAuth] = useState({
isValid: null,
token: null,
user: null
})
//Get User and API Token
useEffect(() => {
const fetchToken = async () => {
try {
const fetchItem = await fetch(
'http://someLocalHost:5000/user',
{
credentials: 'include'
}
)
const fetchResponse = await fetchItem.json();
console.log(fetchResponse)
if (fetchItem.status === 200) {
setAuth({
isValid: true,
token: fetchResponse['token'],
user: fetchResponse['user']
});
}
} catch {
setAuth({isValid: false});
}
};
var intervalCall;
if (auth.isValid === true) {
intervalCall = setInterval(fetchToken, 200000);
} else if (auth.isValid === false) {
return
} else {
fetchToken();
}
return () => {
clearInterval(intervalCall);
};
}, [auth.isValid]);
const authContext = {
user: auth.user,
token: auth.token,
login: (props) => {
setAuth({
isValid: true,
token: props.token,
user: props.user,
})
},
logout: () => {
setAuth({
isValid: false
})
}
}
return (
<div>
<QueryClientProvider client={queryClient}>
<AuthContext.Provider value={authContext}>
<Router>
<Nav />
<main>
<Switch>
<Route path="/" exact component={Index} />
</Switch>
</main>
</Router>
</AuthContext.Provider>
</QueryClientProvider>
</div>
);
}
export default App
我使用react-query来获取、存储和更新API数据。我的组件通常看起来像这样:
function Index() {
const auth = useContext(AuthContext);
);
const usersQuery = useQuery(
'users',
() => fetchData({url: '/users', token: auth.token})
);
return (
<div>
<UserList list={usersQuery.data} />
<NewUser />
</div>
)
}
export default Index
我真的很喜欢invalidateQueries
引起数据重取的能力。New User
组件使用突变,然后使'users'查询无效。
function NewUser() {
const auth = useContext(AuthContext);
const queryClient = useQueryClient()
const newUserMutation = useMutation(formData => fetchPUT({
url: 'new_user',
type: 'PUT',
token: auth.token,
formData: formData
}), {
onSuccess: () => {
queryClient.invalidateQueries('users');
}
});
const addUser = (user_id) => {
var fetchData = new FormData();
fetchData.append('user_id', user_id);
newUserMutation.mutate(fetchData);
};
return (
<div>
<button onClick={() => addUser('someUserID')}>Create New User</button>
</div>
)
}
export default NewUser
这个工作很好,直到200000ms过去,我的根组件获取一个新的身份验证令牌并更新上下文。一旦上下文更新,invalidateQueries
就不会触发,refetchOnWindowFocus
也不会触发。只有刷新才能修复它。我假设这是由反应-查询哈希查询键的方式引起的,所以我试图将身份验证令牌和url添加到查询键数组中,然后在我的fetch函数中使用queryKeys
。
const usersQuery = useQuery(
['users', {url: '/users', token: auth.token}],
fetchData
);
但无济于事。有人知道这是什么原因吗?是我的结构吗?每次上下文更改时都重新安装Index
组件,但对于许多嵌套组件,这将成为一种痛苦。
这是我的组件树的简化结构,只显示相关代码,实际结构更嵌套和复杂。
明白了。最重要的是结构。
如果其他人遇到这个。解决方案如下:
const queryClient = new QueryClient()
每当App
组件的状态发生变化时,都会创建一个新的QueryClient
实例。新客户端没有附加任何旧的挂载查询。最终将所有身份验证移动到子组件,并将QueryClient
和QueryClientProvider
留在根App
元素中,该元素永远不会重新渲染或重新加载