首页 文章

Apollo Client V2以错误的顺序提取数据

提问于
浏览
1

我正在构建一个使用Json Web Tokens授权的应用程序 . 我'm building this application with Node.js, GraphQL and Apollo client V2 (and some other stuff, but those aren'吨在这里相关) . 我创建了一个 login 解析器和一个 currentUser 解析器,让我通过JWT获取当前用户 . 我后来使用该令牌并将其发送到我的授权 Headers 中,结果如下所示:

enter image description here
那部分完成了!但是这里's what I'我遇到了麻烦 .

我试图解释一下情况

我'm using React for the frontend part of this project with the Apollo Client V2. And when I do the login mutation I do it like this. With formik I' ve创建了我的 onSubmit

const response = await mutate({
  variables: {
    email: values.email,
    password: values.password,
  },
})
const token = response.data.login.jwt
localStorage.setItem('token', token)

history.push('/') // Navigating to the home page

这就是我想要的登录变异(只是令牌):

export const loginMutation = gql`
  mutation($email: String!, $password: String!) {
    login(email: $email, password: $password) {
      jwt
    }
  }
`

为了得到 currentUser 's data I' ve,将我的 currentUser query 放入我的根路由器文件中 . Please apologize me for naming the component PrivateRoute. I haven't renamed it yet because I can't find a proper name for it. I'm sorry. 所以 /src/router/index.js 我有这个:

// First the actual query
const meQuery = gql`
{
  currentUser {
    id
    username
    email
  }
}
`

...

// A component that passess the currentUser as a prop, otherwise it will be null
const PRoute = ({ component: Component, ...rest }) => {
  return (
    <Route
      {...rest}
      render={props => {
        return (
          <Component
            {...props}
            currentUser={
              rest.meQuery.currentUser ? rest.meQuery.currentUser : null
            }
          />
        )
      }}
    />
  )
}

// Another component that uses the meQuery so I later can access it if I use the PrivateRoute component.
const PrivateRoute = graphql(meQuery, { name: 'meQuery' })(PRoute)

// Using the PrivateRoute. And in my Home component I can later grap the currentUser via propsb
const App = () => (
  <Router>
    <div>
      <PrivateRoute exact path="/" component={Home} />
...

Home 组件中,我 grab 道具:

const { data: { loading, error, getAllPosts = [], currentUser } } = this.props

我将它传递给我的 Navbar 组件:

<Navbar currentUser={this.props.currentUser} />

Navbar 组件中,如果存在,我会使用用户名:

const { username } = this.props.currentUser || {}

然后我渲染它 .

这就是我遇到的麻烦

当我到达 /login 路线时,我的应用程序正在尝试获取 currentUser . 在我成功进入后,我收回了令牌,但是 currentUser query 没有被取回 . 因此,我必须刷新页面以获取当前用户及其所有值 .

我还创建了一个小视频来演示我的问题 . 我相信它会比我尝试输入它更清楚地显示问题 .

这是视频:https://www.youtube.com/watch?v=GyI_itthtaE

我还要感谢你阅读我的帖子,希望你能帮助我 . 我不知道为什么会发生这种情况,我似乎无法解决它 . 我试着尽可能地写这个问题,很抱歉,如果这是令人困惑的阅读 .

谢谢

2 回答

  • 2

    我想你可以通过将查询的 FetchPolicy 设置为 "cache-and-network" 来解决这个问题 . 你可以阅读有关获取政策的信息here: "GraphQL query options.fetchPolicy"

    在您的具体情况下,我认为您可以更新此行

    const PrivateRoute = graphql(meQuery, { name: 'meQuery' })(PRoute)
    

    对此:

    const PrivateRoute = graphql(meQuery, { name: 'meQuery', options: {fetchPolicy: 'cache-and-network'} })(PRoute)
    

    解释

    如文档中所述,默认策略是cache-first .

    第一次查询

    • currentUser并更新缓存 .

    • 您执行登录变异 cache is not updated 而不更新它(阅读它here: "Updating the cache after a mutation") .

    • currentUser查询再次执行,但由于默认的缓存优先策略,将仅从缓存中检索过期结果 .

    来自official documentation

    cache-first:这是默认值,我们总是首先尝试从缓存中读取数据 . 如果完成查询所需的所有数据都在缓存中,那么将返回该数据 . 如果缓存结果不可用,Apollo将仅从网络中获取 . 此提取策略旨在最大程度地减少呈现组件时发送的网络请求数 . cache-and-network:这个获取策略将让Apollo首先尝试从缓存中读取数据 . 如果完成查询所需的所有数据都在缓存中,那么将返回该数据 . 但是,无论完整数据是否在缓存中,此fetchPolicy将始终使用网络接口执行查询,而不像cache-first,如果查询数据不在缓存中,则只执行查询 . 此提取策略可优化用户获得快速响应,同时还尝试使缓存数据与服务器数据保持一致,但需要额外的网络请求 .

    除了这两个还有两个政策:'network-only'和'cache-only'这里是link to the documentation

  • 1

    对我来说,当我在登录变异中重新获取currentUser查询时,它有效 . 我在下面添加了我的代码 . 也许它有帮助:

    onSubmit(event) {
    event.preventDefault();
    
    const { email, password } = this.state;
    
    this.props
      .mutate({
        variables: { email, password },
        update: (proxy, { data }) => {
          // Get Token from response and set it to the localStorage
          localStorage.setItem('token', data.login.jwt);
        },
        refetchQueries: [{ query: currentUser }]
      })
      .catch((res) => {
        const errors = res.graphQLErrors.map(error => error.message);
        this.setState({ errors });
      });
    }
    

相关问题