使用 google 登录按钮进行反应
Using google sign in button with react
我正在尝试在 React 应用程序中使用 google 登录。
虽然在应用程序本身外部使用登录按钮效果很好,但在自定义 SignIn 组件中使用它时,我无法使其按预期工作。
当用户登录时,按钮本身应该执行 data-onsuccess
方法。
问题是即使登录有效,执行也永远不会到达该方法。
我可能遗漏了一些 React 陷阱,但我真的找不到。有什么帮助吗?在下面找到加载所有内容和组件本身的 html。
<head>
<meta name="google-signin-scope" content="profile email">
<meta name="google-signin-client_id" content="1234-real-client-id.apps.googleusercontent.com">
<script src="https://apis.google.com/js/platform.js" async defer></script>
</head>
<body>
<!-- Here is where everything gets displayed -->
<div id="app"></div>
<!-- The file with the js code -->
<script src="/js/main.js"></script>
</body>
var SignIn = React.createClass({
onSignIn : function (google_user) {
// I want this method to be executed
},
render : function() {
return (
<div className="g-signin2" data-onsuccess={this.onSignIn} data-theme="dark" />
);
}
});
请注意,我没有在此处粘贴不相关的代码 ;)
尝试在 componentDidMount()
中初始化组件时添加 onSuccess 回调。
componentDidMount: function() {
gapi.signin2.render('g-signin2', {
'scope': 'https://www.googleapis.com/auth/plus.login',
'width': 200,
'height': 50,
'longtitle': true,
'theme': 'dark',
'onsuccess': this. onSignIn
});
},
...
来源:https://developers.google.com/identity/sign-in/web/build-button, https://github.com/meta-meta/webapp-template/blob/6d3e9c86f5c274656ef799263c84a228bfbe1725/app/Application/signIn.jsx.
我需要在功能组件中使用它,所以想分享一下我是如何调整它的,我需要使用 useEffectHook 来代替 componentDidMount
useEffect(() => {
window.gapi.signin2.render('g-signin2', {
'scope': 'https://www.googleapis.com/auth/plus.login',
'width': 200,
'height': 50,
'longtitle': true,
'theme': 'dark',
'onsuccess': onSignIn
})
})
现在您可以使用这个封装了所有设置工作的 React Google Login NPM 包。您只能将选项传递给组件。
import React from 'react';
import ReactDOM from 'react-dom';
import GoogleLogin from 'react-google-login';
// or
import { GoogleLogin } from 'react-google-login';
const responseGoogle = (response) => {
console.log(response);
}
ReactDOM.render(
<GoogleLogin
clientId="658977310896-knrl3gka66fldh83dao2rhgbblmd4un9.apps.googleusercontent.com"
buttonText="Login"
onSuccess={responseGoogle}
onFailure={responseGoogle}
cookiePolicy={'single_host_origin'}
/>,
document.getElementById('googleButton')
);
代码来自包的文档。
只需确保将 google 的 platform.js
脚本标记添加到 React 应用的 index.html
:
<script src="https://apis.google.com/js/platform.js" async defer></script>
从以下位置获取您的客户 ID:
https://console.developers.google.com/apis/credentials
编辑 更新了我在部署的生产应用程序中使用的真实实现示例
这里有一个示例 SignInWithGoogle
Typescript 中的函数组件实现,您可以将其用作灵感:
// window.ts
export {};
declare global {
interface Window {
gapi: any;
}
}
// index.tsx
import './window';
import React, {
useEffect,
useState,
} from 'react';
const SignInWithGoogle = () => {
const [loaded, setLoaded] = useState<boolean>(false);
const [signedIn, setSignedIn] = useState<boolean>(false);
const onSignIn = (googleUser: {[k: string]: any}) => {
if (!signedIn) {
setSignedIn(true);
const token = googleUser.getAuthResponse().id_token;
// do something with the token (like send it to your api)...
}
};
const onFail = ({
error,
}: {
error: string;
}) => {
// do something
};
useEffect(() => {
const { gapi } = window;
if (!loaded) {
gapi.load('auth2', () => {
gapi.auth2.init().then((auth: any) => {
auth.signOut().then(() => {
gapi.signin2.render('google-signin-button', {
width: 232,
height: 40,
longtitle: true,
onsuccess: onSignIn,
onfailure: onFail,
});
});
});
setLoaded(true);
});
}
});
return (
<div
id="google-signin-button"
className="google-signin-button"
/>
);
};
export default SignInWithGoogle;
None 其他答案对我有用。最终起作用的是在 div.
上使用 id 而不是 class 作为标识符
<div id="g-signin2" />
而不是
<div className="g-signin2" />
除了按照其他答案的建议使用 window.gapi.signin2.render
。
可能有点晚了,但我想分享我的实施过程。
就我而言,我想完全自定义按钮,并且还想要某种加载程序。我使用 hooks
重新实现了这个
/* istanbul ignore file */
import { useState, useEffect, useCallback } from 'react';
import { APP_IDS } from 'utils/constants';
const initgAuth = () =>
// eslint-disable-next-line no-unused-vars
new Promise((resolve, _reject) => {
// eslint-disable-next-line no-undef
gapi.load('auth2', () => {
// eslint-disable-next-line no-undef
const auth = gapi.auth2.init({
client_id: APP_IDS.Google,
});
resolve(auth);
});
});
const initializeGoogle = () =>
// eslint-disable-next-line no-unused-vars
new Promise((resolve, _reject) => {
if (typeof gapi !== 'undefined') {
window.googleAsyncInit().then(auth => {
resolve(auth);
});
} else {
// eslint-disable-next-line func-names
window.googleAsyncInit = async function() {
const auth = await initgAuth();
resolve(auth);
return auth;
};
// eslint-disable-next-line func-names
(function(d, s, id) {
let js;
const gjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) {
return;
}
// eslint-disable-next-line prefer-const
js = d.createElement(s);
js.id = id;
js.src = 'https://apis.google.com/js/platform.js';
js.onload = window.googleAsyncInit;
gjs.parentNode.insertBefore(js, gjs);
})(document, 'script', 'google_api');
}
});
const useGoogle = () => {
const [google, setGoogle] = useState([]);
const [isReady, setReady] = useState(false);
const initGoogle = useCallback(async () => {
const auth = await initializeGoogle();
if (auth !== 'undefined') {
setGoogle(auth);
setReady(true);
}
});
useEffect(() => {
initGoogle();
}, [initGoogle]);
return [google, isReady];
};
所以我可以像这样在任何组件上使用它
const [GoogleInstance, isGoogleReady] = useGoogle();
GoogleInstance.signIn().then(response => {
const authResponse = response.getAuthResponse(true);
doGoogleLogin(authResponse);
});
这非常方便,因为我能够确保在用户与按钮本身交互之前加载 SDK。如果您有不同的 components/pages 需要 google 登录
,也可以使用
我正在尝试在 React 应用程序中使用 google 登录。
虽然在应用程序本身外部使用登录按钮效果很好,但在自定义 SignIn 组件中使用它时,我无法使其按预期工作。
当用户登录时,按钮本身应该执行 data-onsuccess
方法。
问题是即使登录有效,执行也永远不会到达该方法。
我可能遗漏了一些 React 陷阱,但我真的找不到。有什么帮助吗?在下面找到加载所有内容和组件本身的 html。
<head>
<meta name="google-signin-scope" content="profile email">
<meta name="google-signin-client_id" content="1234-real-client-id.apps.googleusercontent.com">
<script src="https://apis.google.com/js/platform.js" async defer></script>
</head>
<body>
<!-- Here is where everything gets displayed -->
<div id="app"></div>
<!-- The file with the js code -->
<script src="/js/main.js"></script>
</body>
var SignIn = React.createClass({
onSignIn : function (google_user) {
// I want this method to be executed
},
render : function() {
return (
<div className="g-signin2" data-onsuccess={this.onSignIn} data-theme="dark" />
);
}
});
请注意,我没有在此处粘贴不相关的代码 ;)
尝试在 componentDidMount()
中初始化组件时添加 onSuccess 回调。
componentDidMount: function() {
gapi.signin2.render('g-signin2', {
'scope': 'https://www.googleapis.com/auth/plus.login',
'width': 200,
'height': 50,
'longtitle': true,
'theme': 'dark',
'onsuccess': this. onSignIn
});
},
...
来源:https://developers.google.com/identity/sign-in/web/build-button, https://github.com/meta-meta/webapp-template/blob/6d3e9c86f5c274656ef799263c84a228bfbe1725/app/Application/signIn.jsx.
我需要在功能组件中使用它,所以想分享一下我是如何调整它的,我需要使用 useEffectHook 来代替 componentDidMount
useEffect(() => {
window.gapi.signin2.render('g-signin2', {
'scope': 'https://www.googleapis.com/auth/plus.login',
'width': 200,
'height': 50,
'longtitle': true,
'theme': 'dark',
'onsuccess': onSignIn
})
})
现在您可以使用这个封装了所有设置工作的 React Google Login NPM 包。您只能将选项传递给组件。
import React from 'react';
import ReactDOM from 'react-dom';
import GoogleLogin from 'react-google-login';
// or
import { GoogleLogin } from 'react-google-login';
const responseGoogle = (response) => {
console.log(response);
}
ReactDOM.render(
<GoogleLogin
clientId="658977310896-knrl3gka66fldh83dao2rhgbblmd4un9.apps.googleusercontent.com"
buttonText="Login"
onSuccess={responseGoogle}
onFailure={responseGoogle}
cookiePolicy={'single_host_origin'}
/>,
document.getElementById('googleButton')
);
代码来自包的文档。
只需确保将 google 的 platform.js
脚本标记添加到 React 应用的 index.html
:
<script src="https://apis.google.com/js/platform.js" async defer></script>
从以下位置获取您的客户 ID:
https://console.developers.google.com/apis/credentials
编辑 更新了我在部署的生产应用程序中使用的真实实现示例
这里有一个示例 SignInWithGoogle
Typescript 中的函数组件实现,您可以将其用作灵感:
// window.ts
export {};
declare global {
interface Window {
gapi: any;
}
}
// index.tsx
import './window';
import React, {
useEffect,
useState,
} from 'react';
const SignInWithGoogle = () => {
const [loaded, setLoaded] = useState<boolean>(false);
const [signedIn, setSignedIn] = useState<boolean>(false);
const onSignIn = (googleUser: {[k: string]: any}) => {
if (!signedIn) {
setSignedIn(true);
const token = googleUser.getAuthResponse().id_token;
// do something with the token (like send it to your api)...
}
};
const onFail = ({
error,
}: {
error: string;
}) => {
// do something
};
useEffect(() => {
const { gapi } = window;
if (!loaded) {
gapi.load('auth2', () => {
gapi.auth2.init().then((auth: any) => {
auth.signOut().then(() => {
gapi.signin2.render('google-signin-button', {
width: 232,
height: 40,
longtitle: true,
onsuccess: onSignIn,
onfailure: onFail,
});
});
});
setLoaded(true);
});
}
});
return (
<div
id="google-signin-button"
className="google-signin-button"
/>
);
};
export default SignInWithGoogle;
None 其他答案对我有用。最终起作用的是在 div.
上使用 id 而不是 class 作为标识符<div id="g-signin2" />
而不是
<div className="g-signin2" />
除了按照其他答案的建议使用 window.gapi.signin2.render
。
可能有点晚了,但我想分享我的实施过程。 就我而言,我想完全自定义按钮,并且还想要某种加载程序。我使用 hooks
重新实现了这个/* istanbul ignore file */
import { useState, useEffect, useCallback } from 'react';
import { APP_IDS } from 'utils/constants';
const initgAuth = () =>
// eslint-disable-next-line no-unused-vars
new Promise((resolve, _reject) => {
// eslint-disable-next-line no-undef
gapi.load('auth2', () => {
// eslint-disable-next-line no-undef
const auth = gapi.auth2.init({
client_id: APP_IDS.Google,
});
resolve(auth);
});
});
const initializeGoogle = () =>
// eslint-disable-next-line no-unused-vars
new Promise((resolve, _reject) => {
if (typeof gapi !== 'undefined') {
window.googleAsyncInit().then(auth => {
resolve(auth);
});
} else {
// eslint-disable-next-line func-names
window.googleAsyncInit = async function() {
const auth = await initgAuth();
resolve(auth);
return auth;
};
// eslint-disable-next-line func-names
(function(d, s, id) {
let js;
const gjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) {
return;
}
// eslint-disable-next-line prefer-const
js = d.createElement(s);
js.id = id;
js.src = 'https://apis.google.com/js/platform.js';
js.onload = window.googleAsyncInit;
gjs.parentNode.insertBefore(js, gjs);
})(document, 'script', 'google_api');
}
});
const useGoogle = () => {
const [google, setGoogle] = useState([]);
const [isReady, setReady] = useState(false);
const initGoogle = useCallback(async () => {
const auth = await initializeGoogle();
if (auth !== 'undefined') {
setGoogle(auth);
setReady(true);
}
});
useEffect(() => {
initGoogle();
}, [initGoogle]);
return [google, isReady];
};
所以我可以像这样在任何组件上使用它
const [GoogleInstance, isGoogleReady] = useGoogle();
GoogleInstance.signIn().then(response => {
const authResponse = response.getAuthResponse(true);
doGoogleLogin(authResponse);
});
这非常方便,因为我能够确保在用户与按钮本身交互之前加载 SDK。如果您有不同的 components/pages 需要 google 登录
,也可以使用