Skip to content

Instantly share code, notes, and snippets.

@giacomorebonato
Created May 30, 2020 13:24
Show Gist options
  • Save giacomorebonato/cb2a146278c1bf6a6cfc34ce00fec9d1 to your computer and use it in GitHub Desktop.
Save giacomorebonato/cb2a146278c1bf6a6cfc34ce00fec9d1 to your computer and use it in GitHub Desktop.
useAuth authentication hook for React and Apollo
interface Auth {
user?: UserData
login(
email: string,
password: string
): Promise<ExecutionResult<{ login: LOGIN_USER_DATA }>>
logout(): Promise<ExecutionResult<any>>
}
export { AuthProvider } from './useAuth'
export { useAuth } from './useAuth'
import { gql } from 'apollo-boost'
export const MUTATE_LOGOUT = gql`
mutation {
logout
}
`
import { gql } from 'apollo-boost'
export const QUERY_USER = gql`
query {
me {
id
email
}
}
`
export interface QueryUserData {
me: UserData
}
export interface UserData {
id: number
email: string
}
import React from 'react'
import { useQuery, useMutation } from '@apollo/react-hooks'
import { LOGIN_USER_DATA, LOGIN_USER } from '../../mutations/LOGIN_USER'
import { LOGOUT_USER } from '../../mutations/LOGOUT_USER'
import { QUERY_USER, QueryUserData } from './QUERY_USER'
import { Box, Spinner, Button, Text } from '@chakra-ui/core'
const AuthContext = React.createContext<Auth | null>(null)
export const AuthProvider: React.FC = ({ children }) => {
const [mutateLogin] = useMutation<{ login: LOGIN_USER_DATA }>(LOGIN_USER)
const [mutateLogout] = useMutation(LOGOUT_USER)
const { loading, error, data: userData, refetch: refetchUserData } = useQuery<
QueryUserData
>(QUERY_USER)
const login = async (email: string, password: string) => {
return mutateLogin({
variables: {
email,
password
},
update(cache, { data }) {
cache.writeQuery({
query: QUERY_USER,
data: {
me: {
__typename: 'auth',
id: data?.login.user.id,
email: data?.login.user.email
}
}
})
}
})
}
const logout = async () => {
return await mutateLogout({
update(proxy) {
proxy.writeQuery({
query: QUERY_USER,
data: {
me: null
}
})
}
})
}
if (loading) {
return (
<Box>
<Spinner />
</Box>
)
}
if (error) {
return (
<Box>
<Text>Something wrent wrong</Text>
<Button
onClick={() => {
refetchUserData()
}}
>
Try again
</Button>
</Box>
)
}
const user = userData?.me
return (
<AuthContext.Provider value={{ login, logout, user }}>
{children}
</AuthContext.Provider>
)
}
export const useAuth = () => {
const auth = React.useContext(AuthContext)
if (!auth) {
throw new Error('useAuth must be used within a AuthProvider.')
}
return auth
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment