【问题标题】:Graphql query executed only after refreshGraphql 查询仅在刷新后执行
【发布时间】:2020-08-18 15:43:57
【问题描述】:

我正在使用 React、Graphql 和 Apollo。

我的 index.js 如下:

const client = new ApolloClient({
    uri: GRAPHQL_URL,
    fetchOptions: {
        credentials: 'include'
    },
    request: (operation) => {
        const token = localStorage.getItem(AUTH_TOKEN_KEY) || "";
        operation.setContext({
            headers: {
                Authorization: `JWT ${token}`
            }
        })
    },
    clientState: {
        defaults: {
            isLoggedIn: !!localStorage.getItem(AUTH_TOKEN_KEY)
        }
    }
});

const IS_LOGGED_IN_QUERY = gql`
    query {
        isLoggedIn @client
    }
`;

ReactDOM.render(
  <ApolloProvider client={client}>
    <Query query={IS_LOGGED_IN_QUERY}>
        {({data}) => {
            return data.isLoggedIn ? <App/> : <Login/>
        }}
    </Query>
  </ApolloProvider>,
  document.getElementById('root')
);

因此,如果用户已登录,我将令牌保存到 localStorage 并显示 &lt;App /&gt; 而不是 &lt;Login /&gt;

&lt;Login /&gt;如下:

const Login = () => {
    const [username, setUsername] = useState("");
    const [password, setPassword] = useState("");
    const [logIn, { loading: mutationLoading, error: mutationError }] = useMutation(LOG_IN_MUTATION);
    const client = useApolloClient();


    const handleSubmit = async (e) => {
        e.preventDefault();
        const res = await logIn({variables: {username, password}});
        client.writeData({ data: { isLoggedIn: true } })
        localStorage.setItem(AUTH_TOKEN_KEY, res.data.tokenAuth.token);
    };

    return ( ... )

在 de &lt;App /&gt; 中,我对后端进行 Graphql 查询以获取当前登录用户的 de 数据。后端卡住的代码按预期工作。

&lt;App /&gt;如下:

function App() {
    const {loading, error, data} = useQuery(GET_ME);

    if (loading) return <div><LoadingIndicator1/></div>
    if (!loading && error) return <div ><ErrorIndicator/></div>

    return (
        ...
    );
}

export default App;

GET_ME查询如下:

export const GET_ME = gql`
    {
        me{
            id
            username
            firstName
            lastName
            email
        }
    }
`;

退出功能如下:

const client = useApolloClient();

    const signOut = (client) => {
        localStorage.removeItem(AUTH_TOKEN_KEY);
        client.writeData({
            data: {
                isLoggedIn: false
            }
        })
    };

但问题是当我用一个用户登录并注销,然后用另一个用户登录时,我仍然看到旧用户。如果我随后刷新,我会看到新用户。

知道我做错了什么吗?

更新

&lt;App /&gt;组件如下:

function App() {
    const {loading, error, data} = useQuery(GET_ME);

    if (loading) return <div><LoadingIndicator1/></div>
    if (!loading && error) return <div ><ErrorIndicator/></div>

    return (
        <Router>
        <UserContext.Provider value={data.me}>
            <ToastProvider>
                <Header/>
                <Switch>
                    <Route path="/report/:id">
                        <NewReport/>
                    </Route>
                    <Route exact path="/report/">
                        <NewReport/>
                    </Route>
                    <Route path="/reports/">
                        <Reports/>
                    </Route>
                    <Route exact path="/">
                        <Home/>
                    </Route>
                </Switch>
            </ToastProvider>
        </UserContext.Provider>
    </Router>
    );
}

我使用用户详细信息的组件如下:

render (
    <div>
        {localStorage.getItem(AUTH_TOKEN_KEY) !== null && <div>
                        <div className=''>
                           <span>{currentUser.username}</span>
                            <i className="fad fa-angle-down" />
                        </div>
                    </div>}
    </div>
)

【问题讨论】:

  • 您是否在显示用户信息的组件中发送 GET_ME 查询?
  • @Rayneesh 不。我在主组件()中执行此操作,然后通过 React Context 将其传递给所有子组件。
  • 请尝试将查询发送到您显示用户信息的位置并检查是否有帮助
  • @Rajneesh 这不是我想要的。我想在一个地方做,然后作为道具传下去。
  • 所以您通过上下文传递 GET_ME 查询对吗?

标签: reactjs graphql react-apollo apollo-client


【解决方案1】:

我在主组件 () 中执行,然后通过 React Context 将其传递给所有子组件。

我想在一个地方做,然后作为道具传下去。

使用上下文复制已经存在的 apollo 客户端上下文。你可以简单地useQuery 得到相同的结果(cache-only 如果你愿意)。

其他提示:

  • 'main'查询(&lt;Query query={IS_LOGGED_IN_QUERY}&gt;)应该是一个FC(带有useQuery钩子)并组合成&lt;App/&gt;组件;
  • 如果定义了me,则用户已登录(不必要的状态重复) - 您可以将它们组合到一个查询中;
  • 更常见的router auth/private/proteced routes?
  • 过时的方法(apollo 本地状态、路由器)

主要问题

... 可能是由GET_ME 查询的缓存结果引起的。它不是 network-only 也不是由某些用户 id 变量参数化的。

来自 Apollo 文档 (auth):

确保 UI 和商店状态反映当前用户权限的最简单方法是在您的登录或注销过程完成后调用 client.resetStore()

【讨论】:

    猜你喜欢
    • 2013-09-05
    • 1970-01-01
    • 1970-01-01
    • 2018-10-07
    • 2021-03-08
    • 2019-03-02
    • 2021-01-18
    • 1970-01-01
    • 2019-04-04
    相关资源
    最近更新 更多