【问题标题】:useQuery returns undefined after redirect with useMutations [Apollo/React hooks]使用 useMutations [Apollo/React hooks] 重定向后 useQuery 返回 undefined
【发布时间】:2020-01-02 02:40:12
【问题描述】:

在我的应用程序中,我有 2 个公共路由(登录和注册页面)和一个 PrivateRoute,它使用 JWT 验证 localStorage 中的“auth-token”是否有效。

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

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

问题是,在用户成功注册后被重定向到聊天室后,useMutations 速度过快并返回 undefined。如果我刷新页面,它会完美地获取“我”查询。

我已经尝试在重定向上使用 setTimeout,因为它可能是令牌设置得不够快。但事实并非如此。

我尝试过使用 useLazyQuery 钩子,但也没有用。它还需要刷新,因为第一次它也给出了 undefined。


/// 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:设置 TimeOut 不适用于 'props.history.push('/')'

编辑 2:找到解决方案。由于这是我使用 GraphQL 和 Apollo 的第一个项目,我不知道 Apollo Boost 就像来自 Apollo 的 create-react-app,我需要使用 Apollo-Client(更可定制的包)配置所有内容。我按照official docs hereApollo Boost 迁移到客户端。

【问题讨论】:

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


    【解决方案1】:

    我认为localStorage.setItem 是一个异步函数。问题是你已经推送了路由,虽然它还没有完成将令牌写入 localStorage。

    对此我的 hack 解决方案是在您推送路线之前添加延迟

    
        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}`
          }
        }
      })
    

    【讨论】:

    • 嗨,我已经尝试在重定向上使用 setTimeout,因为它可能是令牌设置得不够快。但事实并非如此。 ...该死的...即使我将其设置为 5000 毫秒,它也需要刷新才能运行...
    • 你的意思是它仍然没有从 localStorage 获取 auth-token 吗?
    • 这可能与我的 apolloClient 设置(与 apollo-boost 相关)有关吗?我编辑了原始帖子...
    • 我怀疑您的服务器正在等待承载授权,而您没有提供令牌。像这样github.com/jasper95/interlink-graphql/blob/master/src/apollo/…
    • 将从 Apollo boost 迁移到 Apollo Client,看看这是否会更好。感谢您的帮助和链接 :) 会回复您 :)
    【解决方案2】:

    这可能与我的客户端设置有关吗? 它使用 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);
    

    【讨论】:

      猜你喜欢
      • 2021-11-04
      • 2020-10-30
      • 2019-09-14
      • 2019-10-06
      • 2019-11-19
      • 2021-10-10
      • 2020-11-19
      • 2020-01-23
      • 1970-01-01
      相关资源
      最近更新 更多