我正在尝试实现Apollo docs中正式描述的身份验证工作流,就像我之前在其他项目中所做的那样,但这次使用 Gatsby 。
这个想法似乎很简单。需要创建/更新gatsby-browser.js
,例如在使用redux时,但要初始化ApolloClient
并通过ApolloProvider
。
类似的东西:
import React from 'react'
import { Router } from 'react-router-dom'
import { ApolloProvider } from 'react-apollo'
import { ApolloClient } from 'apollo-client'
import { createHttpLink } from 'apollo-link-http'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { setContext } from 'apollo-link-context'
const httpLink = createHttpLink({
uri: process.env.ENDPOINT_URI,
credentials: 'same-origin',
})
const authLink = setContext((_, { headers }) => {
const token = localStorage.getItem('token');
return {
headers: {
...headers,
authorization: token ? `Bearer ${token}` : "",
}
}
})
const client = new ApolloClient({
link: authLink.concat(httpLink),
cache: new InMemoryCache().restore({}),
})
exports.replaceRouterComponent = ({ history }) => {
const ConnectedRouterWrapper = ({ children }) => (
<ApolloProvider client={client}>
<Router history={history}>{children}</Router>
</ApolloProvider>
)
return ConnectedRouterWrapper
}
然后使用
登录<Mutation
mutation={LOGIN_MUTATION}
refetchQueries={[{ query: CURRENT_USER_QUERY }]}
>
{/*...*/}
</Mutation>
和另一个组件中的状态(其中,如果登录则显示x,否则为y):
<Query query={CURRENT_USER_QUERY} fetchPolicy="network-only">
{/*...*/}
</Query>
问题
使用此配置,当登录收到data
(因此,凭据正常)时,我保存在localStorage
中收到的令牌,但状态组件执行{{ 1}}使用上一个(空)Query
,因此显示已注销,登录后也会执行类似token
的操作。
刷新页面,因为history.push('/')
中的项目之前已保存,状态显示为已登录。
预期行为
我的想法是在登录后更新 Status 组件,避免刷新页面,因此我添加了localStorage
。
我尝试了一些诸如传递refetchQueries={[{ query: CURRENT_USER_QUERY }]}
之类的内容(如果我更改props
并在状态组件中使用route
则不需要),但似乎迟到,withRouter
在没有新Query
的情况下被解雇。
答案 0 :(得分:0)
这里的主要问题可能是您的状态组件只有在将令牌保存到localStorage
后才需要重新呈现。现在它可能过早重新渲染。
您可以尝试使用其他包装器组件包装 Status 组件,并在呈现 Status 组件之前检查令牌是否存在。
答案 1 :(得分:0)
我认为您的问题与链接的定义方式有关。 IMO,AuthLink应该在HttpLink之前定义(作为中间件):
const client = new ApolloClient({
link: ApolloLink.from([
authLink,
httpLink
]),
cache: new InMemoryCache().restore({}),
})
虽然文档说concat和from做同样的事情,但顺序很重要。您希望在发送请求之前设置上下文。