Re-fetchingparent'currentUser'child组件使用Apollo登录后的数据

Re-fetching parent 'currentUser' data after child component logs in using Apollo

我正在使用 apollo-client 并通过 header 连接到使用 express-jwt 进行身份验证的快速服务器。我当前的客户端组件如下所示:App -> Login.

这是我的客户端初始化文件的样子 (index.js)。为了简洁起见,我省略了不必要的代码:

const authLink = setContext((_, { headers }) => {
  const token = localStorage.getItem('token');

  return {
    headers: {
      ...headers,
      Authorization: token ? `Bearer ${token}` : null
    }
  };
});

const client = new ApolloClient({
  link: authLink.concat(new HttpLink({ uri: '/graphql' })),
  cache: new InMemoryCache()
});

这基本上是设置 Apollo 中间件,它在 localStorage 中检查 token 并将其添加到每个后续请求的 header 中,以便我的登录用户可以通过身份验证。这是我的 top-level App 组件(使用 react-router v4 - 省略了不相关的代码):

class App extends Component {
  render() {
    const { currentUser } = this.props.data;
    console.log(currentUser);

    return (
       <Switch>
          <Route
            path="/login"
            render={routeProps => <Login {...routeProps} {...this.props} />}
          />
        </Switch>
    );
  }
}

export default graphql(currentUserQuery, {
  options: { fetchPolicy: 'network-only' }
})(withRouter(App));

您可能猜到了,当我的 App 组件创建时,它会调用 currentUserQuery 从我的 graphql 端点检索当前用户。这是我的 Login 组件的相关代码:

class Login extends Component {
  handleSubmit = async e => {
    e.preventDefault();

    this.props
      .mutate({
        variables: { email: this.state.email, password: this.state.password }
      })
      .then(result => {
        const { jwt } = result.data.login;
        if (jwt) {
          localStorage.setItem('token', jwt);
          this.props.history.push('/');
          return;
        }
      })
      .catch(error => {
        console.log(error.message);
      });
  };
}

export default graphql(userLoginMutation)(Login);

我的问题是,一旦我的 userLoginMutation 成功,我想返回到我的 App 组件并希望在那里看到我的 currentUser object。不幸的是 App 组件不会触发新的 graphql 查询来尝试获取 currentUser object 当我路由回它时。我还尝试在登录突变上使用 Apollo 的 refetchQueries 方法来尝试重新获取当前用户,但是在登录承诺完成并且令牌尚未在中间件中之前运行查询,因此请求不执行任何操作.值得注意的是,如果我只是在页面上进行硬刷新,我就可以访问我的 currentUser object,因为它从 localStorage 中提取令牌并将其正确放置在中间件中。

如有任何帮助或建议,我们将不胜感激。

我们需要一种方法来在 localStorage 更新之后但在您导航离开之前触发唯一的重新获取。这是一种方法:将 Login 组件与 currentUser 查询的另一个 HOC 包装起来:

export default compose(
  graphql(userLoginMutation),
  graphql(currentUserQuery),
)(MyComponent)

现在你的组件的 props 将同时包括 mutatedata,所以我们可以这样做:

this.props.mutate({
  variables: { email: this.state.email, password:this.state.password}
})
  .then(result => {
    const { jwt } = result.data.login;
    if (jwt) {
      localStorage.setItem('token', jwt);
      return this.props.data.refetch()
    }
    // if there's no jwt, we still want to return a Promise although
    // you could do Promise.reject() instead and trigger the catch
    return Promise.resolve();
  })
  .then(() => this.props.history.push('/'))
  .catch(error => {
    console.log(error.message);
  });