I wanted to implement login with google feature on my React native app. I'm using expo-cli
and I used expo authSession
for this.
LoginScreen.js
import * as React from "react";
import * as WebBrowser from "expo-web-browser";
import * as Google from "expo-auth-session/providers/google";
import { Button, View, Text, TouchableOpacity } from "react-native";
WebBrowser.maybeCompleteAuthSession();
export default function LoginScreen() {
const [googleAccessToken, setGoogleAccessToken] = React.useState(null);
const [userInfo, setUserInfo] = React.useState(false);
const [request, response, promptAsync] = Google.useAuthRequest({
expoClientId: "###",
iosClientId: "###",
androidClientId: "###",
webClientId: "###",
});
React.useEffect(() => {
if (response?.type === "success") {
const { authentication } = response;
setGoogleAccessToken(authentication.accessToken);
fetchUserInfo();
}
}, [response]);
const fetchUserInfo = () => {
if (googleAccessToken) {
fetch("https://www.googleapis.com/oauth2/v3/userinfo", {
headers: { Authorization: `Bearer ${googleAccessToken}` },
})
.then((response) => response.json())
.then((userInfoObj) => {
setUserInfo(userInfoObj);
console.log(userInfoObj);
})
.catch((err) => {
console.log(err);
});
}
};
return (
<View>
<Button
disabled={!request}
title="Login Here"
onPress={() => {
promptAsync();
}}
/>
{userInfo ? <Text>{userInfo.email}</Text> : <Text>Nope</Text>}
</View>
);
}
But once, I click LOGIN HERE
button and login with google account it doesn't set userInfo
state in the first time. I have to click LOGIN HERE
button again to login. Even though I have authenticated with google, it doesn't set userInfo
state in the first time. But once I click LOGIN HERE
again and after continue the process, then it works. How can I solve this issue?
Also I'm getting this warning as well.
Warning
EventEmitter.removeListener('url', ...): Method has been deprecated. Please instead use `remove()` on the subscription returned by `EventEmitter.addListener`.
at node_modules/react-native/Libraries/vendor/emitter/_EventEmitter.js:164:4 in EventEmitter#removeListener
at node_modules/react-native/Libraries/EventEmitter/NativeEventEmitter.js:108:4 in removeListener
at node_modules/react-native/Libraries/Linking/Linking.js:57:4 in removeEventListener
at node_modules/expo-web-browser/build/WebBrowser.js:354:4 in _stopWaitingForRedirect
at node_modules/expo-web-browser/build/WebBrowser.js:347:31 in _openAuthSessionPolyfillAsync
I found the answer for this question by myself. You need to put fetchUserInfo()
inside useEffect.
import * as React from "react";
import * as WebBrowser from "expo-web-browser";
import * as Google from "expo-auth-session/providers/google";
import { Button, View, Text, TouchableOpacity } from "react-native";
WebBrowser.maybeCompleteAuthSession();
export default function LoginScreen() {
const [googleAccessToken, setGoogleAccessToken] = React.useState(null);
const [userInfo, setUserInfo] = React.useState(false);
const [request, response, promptAsync] = Google.useAuthRequest({
expoClientId: "###",
iosClientId: "###",
androidClientId: "###",
webClientId: "###",
});
React.useEffect(() => {
const fetchUserInfo = () => {
if (googleAccessToken) {
fetch("https://www.googleapis.com/oauth2/v3/userinfo", {
headers: { Authorization: `Bearer ${googleAccessToken}` },
})
.then(response => response.json())
.then(userInfoObj => {
setUserInfo(userInfoObj);
console.log(userInfoObj);
})
.catch(err => {
console.log(err);
});
}
};
if (response?.type === "success") {
const { authentication } = response;
setGoogleAccessToken(authentication.accessToken);
fetchUserInfo();
}
}, [response]);
return (
<View>
<Button
disabled={!request}
title="Login Here"
onPress={() => {
promptAsync();
}}
/>
{userInfo ? <Text>{userInfo.email}</Text> : <Text>Nope</Text>}
</View>
);
}