问题
I have this class based component using the gapi (Google Auth) API that renders a button and it works:
import React from 'react';
class GoogleAuth extends React.Component {
state = { isSignedIn: null };
componentDidMount() {
window.gapi.load('client:auth2', () => {
window.gapi.client
.init({
clientId: process.env.REACT_APP_CLIENT_ID,
scope: 'email',
})
.then(() => {
this.auth = window.gapi.auth2.getAuthInstance();
this.handleAuthChange();
this.auth.isSignedIn.listen(this.handleAuthChange);
});
});
}
handleAuthChange = () => {
this.setState({ isSignedIn: this.auth.isSignedIn.get() });
};
handleSignIn = () => {
this.auth.signIn();
};
handleSignOut = () => {
this.auth.signOut();
};
renderAuthButton() {
if (this.state.isSignedIn === null) {
return null;
} else if (this.state.isSignedIn) {
return <button onClick={this.handleSignOut}>Sign Out</button>;
} else {
return <button onClick={this.handleSignIn}>Sign in with Google</button>;
}
}
render() {
return <div>{this.renderAuthButton()}</div>;
}
}
export default GoogleAuth;
I'm having a tough time trying to convert this to use hooks. The main issue is this.auth
... That's how the class has a reference to window.gapi.auth2.getAuthInstance()
I have tried many different ways including keeping auth in state like:
export default function GoogleAuth() {
const [isSignedIn, setIsSignedIn] = useState(null);
const [auth, setAuth] = useState(null);
useEffect(() => {
window.gapi.load('client:auth2', () => {
window.gapi.client
.init({
clientId: process.env.REACT_APP_CLIENT_ID,
scope: 'email',
})
.then(() => {
setAuth(window.gapi.auth2.getAuthInstance());
setIsSignedIn(auth.isSignedIn.get());
auth.isSignedIn.listen(() => setIsSignedIn(auth.isSignedIn.get()));
});
});
}, [auth]);
回答1:
Couple issues - you're referencing auth
immediately after you're setting the state - auth
won't be set until it re-renders with its new state.
I'm playing with similar code, and I had to resort to utilizing window.gapi
in the initial setup to properly access the returned auth instance.
I imagine it may throw an error if a user clicks quickly they could catch it before auth
is set, but I found the sign in/out functions to be able to handle this.
I also found it easiest to test in Incognito, as cookies and cacheing of the api seemed to create an unpredictable local testing environment.
My current component state
回答2:
It's only 8 months later but try useRef with auth like below. It works for me.
const GoogleAuth = () => {
const [isSignedIn, setSignedIn] = useState(null)
const auth = useRef(null);
useEffect(() => {
window.gapi.load('client:auth2', () => {
window.gapi.client.init({
clientId:
'jcu.apps.googleusercontent.com',
scope: 'email'
}).then(() => {
auth.current = window.gapi.auth2.getAuthInstance();
setSignedIn(auth.current.isSignedIn.get());
auth.current.isSignedIn.listen(onAuthChange)
});
});
}, [isSignedIn]);
const onAuthChange = () => {
setSignedIn(auth.current.isSignedIn.get())
}
if (isSignedIn === null) {
return (
<div>I don't know if we are signed in!</div>
);
} else if ( isSignedIn ){
return (
<div>I am signed in!</div>
);
} else {
return ( <div>I am not signed in. :(</div>);
}
}
来源:https://stackoverflow.com/questions/55961293/converting-a-class-based-component-to-hooks-gapi-api