I am new to react native and I cannot get this authentication flow to work. I have tried all I can think of but it will not work. Here is my Code
auth.js
import React, { useReducer,createContext } from 'react';
import jwtDecode from 'jwt-decode';
import AsyncStorage from '@react-native-async-storage/async-storage';
const initialState = {
user:null
}
let token;
const getToken = async () => {
if (token) {
return Promise.resolve(token);
}
token = await AsyncStorage.getItem('jwtToken');
return token;
};
const AuthContext = createContext({
user:null,
login:(userData) => {},
logout:() => {}
})
function authReducer(state, action){
switch(action.type){
case 'LOGIN':
return{
...state,
user:action.payload
}
case 'LOGOUT':{
return{
...state,
user:null
}
}
default:
return state;
}
}
function AuthProvider(props){
const [state,dispatch] = useReducer(authReducer, initialState);
const login = async (userData) => {
try {
await AsyncStorage.setItem("jwtToken", userData.token)
dispatch({
type:'LOGIN',
payload: userData
})
} catch(e){
console.log(e)
}
}
const logout = async () => {
try {
await AsyncStorage.removeItem('jwtToken')
dispatch({
type:"LOGOUT"
});
} catch(e){
console.log(e)
}
}
console.log(state)//user object is here, but is not set in AuthContext, I cant get it from my App.js
return (
<AuthContext.Provider
value={{ user:state.user, login, logout }}
{...props}
/>
)
}
export { AuthContext, AuthProvider, getToken }
As I mentioned in the code above, my User object from my graphql server is obtained here and is console logged correctly, I get the token along with everything else in the graphql mutation at the end of Login.js below
Here is My Login.js screen
import React,{ Component,useContext, useState } from 'react'
//import { useForm } from '../util/hooks';
import { useMutation } from '@apollo/react-hooks';
import gql from 'graphql-tag';
import { Alert, Button, FlatList, Text, TouchableHighlight, TextInput, View, StyleSheet } from 'react-native';
import { AuthContext } from '../context/auth';
function Login(props) {
const context = useContext(AuthContext)
const [username,setUsername] = useState('')
const [password,setPassword] = useState('')
const [errors, setErrors] = useState({})
const [loginUser, { loading }] = useMutation(LOGIN_USER, {
update(_, { data: { login: userData }}){cache
context.login(userData)
},
onError(err){
//error handling
},
variables: {username,password}
});
const onSubmit = () =>{
loginUser();
}
const createTwoButtonAlert = (value) =>{
//Alert in case of errors here also works with server side verification
return (
// JSX STUFF HERE
)
}
const LOGIN_USER = gql`
mutation login(
$username:String!
$password:String!
){
login(
username:$username
password:$password
) {
id email username createdAt token
}
}
`;
And finally my App.js file, after logging in I try to obtain the user object from my AuthContext but if I console log the context, it comes up as the initial context from above, Ill explain below
App.js
//other imports
import { NavigationContainer } from '@react-navigation/native';
import { createStackNavigator } from '@react-navigation/stack';
import { AuthProvider } from './context/auth';
import { AuthContext } from './context/auth';
import { getToken } from './context/auth';
import Login from './components/Login';
import Register from './components/Register';
import Landing from './components/Landing';
const authLink = setContext(async (req, { headers }) => {
const token = await getToken();
return {
...headers,
headers: {
authorization: token ? `Bearer ${token}` : null,
},
};
});
const httpLink = createHttpLink({
uri: 'http://192.168.0.8:5000/graphql',
});
const client = new ApolloClient({
link: authLink.concat(httpLink),
cache: new InMemoryCache()
});
const Stack = createStackNavigator()
export default function App() {
const context = useContext(AuthContext)
console.log(context) /// this returns the initially set context, its never changed
return(
<ApolloProvider client={client}>
<AuthProvider>
<NavigationContainer>
<Stack.Navigator>
{context.user && (
<Stack.Screen name="Landing" component={Landing} options={{ headerShown: false }} />
)}
{!context.user && (
<>
<Stack.Screen name="Landing" component={Landing} options={{ headerShown: false }} />
<Stack.Screen name="Register" component={Register} />
<Stack.Screen name="Login" component={Login} />
</>
)}
</Stack.Navigator>
</NavigationContainer>
</AuthProvider>
</ApolloProvider>
)
}
I am using the latest versions of all packages
question from:
https://stackoverflow.com/questions/65876642/createcontext-not-working-on-my-react-native-app-with-apollo-client-and-graph-ql