React中Async函数无法访问this,Apollo Client登录重查USER查询受阻
解决React + Apollo Client登录后refetch停滞的问题
嘿,我之前在做Apollo项目时也踩过类似的this上下文坑,咱们一步步来搞定它~
首先你推测的方向完全正确:类组件里的async方法如果没正确绑定this,确实会导致this.props指向异常,进而调用refetch时卡住或者静默报错。下面给你几个靠谱的解决方案:
方案1:用箭头函数定义login方法
箭头函数会自动绑定当前组件的this上下文,不用手动处理绑定,这是最简洁的方式:
login = async () => { try { const result = await this.props.LoginMutation({ variables: { email: this.state.email, password: this.state.password }, }); // 先处理token存储(比如存到localStorage) const token = result.data.authenticate.token; localStorage.setItem('authToken', token); // 现在调用refetch就不会因为this指向问题卡住了 await this.props.USER.refetch(); // 根据用户资料跳转 const user = this.props.USER.data.user; if (user.isAdmin) { this.props.history.push('/admin-dashboard'); } else { this.props.history.push('/user-profile'); } } catch (error) { // 别忘了处理登录或refetch时的错误 console.error('登录或获取用户信息失败:', error); } }
方案2:在构造函数中手动绑定this
如果习惯用普通函数定义方法,就在组件的构造函数里绑定this到组件实例:
constructor(props) { super(props); this.state = { email: '', password: '' }; // 绑定login方法的this this.login = this.login.bind(this); } async login() { // 这里的this就会正确指向组件实例了 const result = await this.props.LoginMutation({ variables: { email: this.state.email, password: this.state.password }, }); const token = result.data.authenticate.token; localStorage.setItem('authToken', token); await this.props.USER.refetch(); // 跳转逻辑... }
方案3:提前解构props,避开this依赖
在login方法内部先解构出需要的方法,完全不用依赖this:
async login() { // 提前解构出mutation和refetch方法 const { LoginMutation, USER: { refetch } } = this.props; const { email, password } = this.state; const result = await LoginMutation({ variables: { email, password }, }); const token = result.data.authenticate.token; localStorage.setItem('authToken', token); // 直接调用解构出来的refetch,彻底避开this问题 await refetch(); // 跳转逻辑... }
额外注意:确保Apollo Client能拿到登录后的token
除了this的问题,还要确认登录后的token已经被Apollo Client正确携带,不然USER查询会因为权限不足卡住。可以在Apollo Client初始化时配置请求拦截器:
import { ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client'; import { setContext } from '@apollo/client/link/context'; const httpLink = createHttpLink({ uri: '/your-graphql-endpoint', }); const authLink = setContext((_, { headers }) => { // 从localStorage获取token const token = localStorage.getItem('authToken'); // 返回带token的请求头 return { headers: { ...headers, authorization: token ? `Bearer ${token}` : '', }, }; }); const client = new ApolloClient({ link: authLink.concat(httpLink), cache: new InMemoryCache(), });
这样refetch的时候,请求头里就会带上刚登录拿到的token,确保USER查询能正常返回数据。
内容的提问来源于stack exchange,提问作者Evanss
相关产品推荐
相关产品推荐

