【问题标题】:How to invalidateQueries with JWT Tokens in the Context?如何在上下文中使用 JWT 令牌使查询无效?
【发布时间】:2021-02-10 03:19:28
【问题描述】:

我正在使用短期 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 组件使用突变,然后使“用户”查询无效。

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

这很好用,直到 200000 毫秒过去,我的根组件获取一个新的身份验证令牌并更新上下文。一旦上下文更新invalidateQueries 不会触发并且refetchOnWindowFocus 不会触发。只有刷新修复它。我假设它是由 react-query 散列查询键的方式引起的,所以我尝试将身份验证令牌和 url 添加到查询键数组中,然后在我的 fetch 函数中使用queryKeys

const usersQuery = useQuery(
    ['users', {url: '/users', token: auth.token}],
    fetchData
);

但无济于事。有谁知道是什么原因造成的?是我的结构吗?每次上下文更改起作用时都重新安装 Index 组件,但是对于许多嵌套组件,这将变得很痛苦。

这是我的组件树的简化结构,只显示相关代码,实际结构更加嵌套和复杂。

【问题讨论】:

    标签: reactjs react-router react-context react-query


    【解决方案1】:

    想通了。一切都与结构有关。
    如果其他人遇到这种情况。这是解决方案:

    const queryClient = new QueryClient()
    

    每当App 组件的状态发生变化时,这都会创建一个新的QueryClient 实例。新客户端没有附加任何旧的已安装查询。 最终将所有身份验证移至子组件,并将 QueryClientQueryClientProvider 留在根 App 元素中,永远不会重新渲染或重新安装

    【讨论】:

      猜你喜欢
      • 2020-02-09
      • 2016-12-03
      • 2015-05-19
      • 2015-05-06
      • 2021-04-13
      • 2022-07-08
      • 2016-12-23
      • 2019-01-12
      相关资源
      最近更新 更多