在我的应用程序中,我有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
到客户端的迁移。
答案 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);