使用useMutations重定向后,useQuery返回未定义的[Apollo / React hooks]

时间:2019-08-28 20:33:35

标签: reactjs react-router-dom react-apollo apollo-client graphql-js

在我的应用程序中,我有2条公共路由(“登录和注册”页面)和一条PrivateRoute,如果localStorage中的“ auth-token”有效,则会通过JWT进行验证。

在“注册”页面中,我使用“ useMutations”钩子来注册用户。我在LocalStorage中设置了一个令牌,并使用react路由器将其发送到聊天的主要组件('/')。

我进行了“我”查询,需要我的“身份验证令牌”才能从数据库中获取特定用户。

问题是,在用户成功注册后重定向到聊天之后,useMutations进行得太快并且返回未定义。如果我刷新页面,它将完美地获取“我”查询。

我已经尝试在重定向上使用setTimeout,因为它可能是令牌设置得不够快的原因。但这不是。

我已经尝试过useLazyQuery钩子,但这也不起作用。它也需要刷新,因为它第一次也给出了不确定的信息。


/// my register component ///

const Register = props => {
  const [createUser] = useMutation(CREATE_USER, {
    onCompleted({ createUser }) {
      localStorage.setItem('auth-token', createUser.token);
      props.history.push('/');
    }
  });

  return (
    <InputWrapper>
      <h2>Signup for DevChat</h2>
      {/* {error !== null && <Alert>{error}</Alert>} */}

      <Formik
        initialValues={{
          userName: '',
          email: '',
          password: '',
          confirmPassword: ''
        }}
        validationSchema={RegisterSchema}
        onSubmit={(values, { resetForm }) => {
          createUser({ variables: values });
          resetForm({
            userName: '',
            email: '',
            password: '',
            confirmPassword: ''
          });
        }}
      >


const UserPanel = () => {
  const { data, loading, error } = useQuery(GET_LOGGED_IN_USER, {
    context: localStorage.getItem('auth-token')
  });

  const [toggleOn, setToggleOn] = useState(false);

  const handleSignOut = () => {
    localStorage.removeItem('auth-token');
    ///refresh page should redirect to /login
    window.location.reload();
  };

  const toggleDropDown = () => {
    setToggleOn(!toggleOn);
  };

  return (
    <ProfileWrapper>
      {loading ? <span>Loading ...</span> : console.log(data)}

      <ProfileGroup onClick={toggleDropDown}>
        <ProfileIcon className='fas fa-user' />
        <ProfileTitle>
          {/* {loading && called ? <span>Loading ...</span> : console.log(data)} */}
          {error ? console.log(error) : null}
        </ProfileTitle>
        <DropDownIcon
          className={toggleOn ? 'fas fa-chevron-up' : 'fas fa-chevron-down'}
        />


/// my console.log(the first time)
undefined
UserPanel.js:95 Error: GraphQL error: jwt malformed

UserPanel.js:91 {}

/// my console.log() after a refresh:

{me: {…}}
me:
age: null
email: "test@gmail.com"
id: "599c5f9a-f97e-4964-a707-138c2159cff8"
userName: "Test"
__typename: "User"
__proto__: Object

想知道我在做什么错...预先感谢您的帮助和阅读... :)

伯特

编辑1:在'props.history.push('/')'上设置超时无效

编辑2:找到解决方案。因为这是我使用GraphQL和Apollo的第一个项目,所以我不知道Apollo Boost就像Apollo的create-react-app一样,我需要使用Apollo-Client(更可自定义的软件包)进行配置。我遵循official docs here进行从Apollo Boost到客户端的迁移。

2 个答案:

答案 0 :(得分:0)

我认为localStorage.setItem是一个异步函数。问题是,尽管您尚未完成将令牌写入localStorage的操作,但是您已经推送了路由。

为此,我的黑客解决方案是在您推路线之前增加了延迟


    onCompleted({ createUser }) {
      localStorage.setItem('auth-token', createUser.token);
      setTimeout(() => {
        props.history.push('/');
      }, 500)
    }

编辑:问题似乎是阿波罗客户端初始化

  const httpAuthLink = setContext((_, { headers }) => {
    const token = localStorage.getItem('token')
    return {
      headers: {
        ...headers,
        Authorization: `Bearer ${token}`
      }
    }
  })

答案 1 :(得分:0)

这与我的客户端设置有关吗? 它带有apollo-boost软件包,而不是apollo-client ...


import React from 'react';
import {
  BrowserRouter as Router,
  Switch,
  Route,
  withRouter
} from 'react-router-dom';
import { ApolloProvider } from '@apollo/react-hooks';
import ApolloClient, { InMemoryCache } from 'apollo-boost';
import Login from './components/auth/Login';
import Register from './components/auth/Register';
import Chat from './components/pages/Chat';
import PrivateRoute from './components/auth/PrivateRoute';

// const cache = new InMemoryCache();

const client = new ApolloClient({
  uri: 'http://localhost:4000/',
  headers: {
    Authorization: `Bearer ${localStorage.getItem('auth-token')}`
  }
});

const App = () => {
  return (
    <ApolloProvider client={client}>
      <Router>
        <Switch>
          <PrivateRoute exact path='/' component={Chat} />
          <Route path='/register' component={Register} />
          <Route path='/login' component={Login} />
        </Switch>
      </Router>
    </ApolloProvider>
  );
};

const RootWithAuth = withRouter(App);