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 将同时包括 mutate
和 data
,所以我们可以这样做:
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);
});
我正在使用 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 将同时包括 mutate
和 data
,所以我们可以这样做:
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);
});