Reputation: 435
I'm trying to use the reCaptcha integrated in firebase authentication with React and Redux.
const Login = props => {
useEffect(() => {
window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('login-button', {
'size': 'invisible',
'callback': () => login()
}
);
window.recaptchaVerifier.render()
}, []);
function login() {
console.log(props)
firebaseLogin(props.email, props.password).then(() => {
...
}
).catch(function (error) {
console.log(error);
...
});
}
function onChangePassword(event) {
props.onChangePassword(event.target.value)
}
function onChangeEmail(event) {
props.onChangeEmail(event.target.value)
}
return (
...
<form>
<label>Dirección de Email</label>
<div className="form-group">
<input type="email"
className={`form-control ${emailValidation ? "is-invalid" : ""}`}
placeholder="[email protected]"
onChange={onChangeEmail} value={props.email} tabIndex={1}
autoComplete={"username"}
required/>
<div className="invalid-feedback">
{emailValidation}
</div>
</div>
<div className="form-group">
<div className="row">
<div className="col">
<label>Contraseña</label>
</div>
<div className="col-auto">
<Link to="/reset-password" className="form-text small text-muted">
Olvidé mi contraseña
</Link>
</div>
</div>
<div className="input-group input-group-merge">
<input type={showPassword ? "text" : "password"}
className={`form-control ${passwordValidation ? "is-invalid" : ""} form-control-appended`}
placeholder="Ingrese su contraseña" onChange={onChangePassword}
value={props.password} required tabIndex={2}
autoComplete={"current-password"}/>
<div className="input-group-append">
<span className="input-group-text clickable"
onClick={() => setShowPassword(!showPassword)}>
<i className="fe fe-eye"/>
</span>
</div>
<div className="invalid-feedback">
{passwordValidation}
</div>
</div>
</div>
<button type="submit" className="btn btn-lg btn-block btn-primary mb-3"
id={"login-button"}
tabIndex={3}>
Acceder
</button>
</form>
...
)
};
const mapDispatchToProps = dispatch => ({
onChangeEmail: value =>
dispatch({type: UPDATE_LOGIN_FIELD, key: 'formEmail', value}),
onChangePassword: value =>
dispatch({type: UPDATE_LOGIN_FIELD, key: 'password', value}),
});
const mapStateToProps = state => ({
email: state.authentication.formEmail,
password: state.authentication.password,
});
export default connect(mapStateToProps, mapDispatchToProps)(Login);
The problem is that in the login callback the props are outdated and doesn't contain the email and password that are loaded in the redux store, it just contains the props that were available when the useEffect was triggered. (I see that with the console.log(props))
I don't know how can I keep a reference to the updated props. I've tried using the useRef hook and sending it to the login as a parameter, but that didn't work either.
I've also tried using the email and password props as useEffect dependencies, but that triggers the recaptcha generation a lot of times and it's very inefficient.
Thanks for your help!
Upvotes: 0
Views: 932
Reputation: 435
Seems to work as
window.login = useCallback(() => {
console.log(props);
firebaseLogin(props.email, props.password).then(() => {
...
}
).catch(function (error) {
console.log(error);
....
}
}, [props]);
useEffect(() => {
window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier('login-button', {
'size': 'invisible',
'callback': () => window.login(),
}
);
window.recaptchaVerifier.render();
}, []);
There is another problem, but not related to this question
Upvotes: 2
Reputation: 4635
Use the callback hook to access the latest state in a performant manner.
const login = useCallback( () => {
console.log(props)
firebaseLogin(props.email, props.password).then(() => {
...
}
).catch(function (error) {
console.log(error);
...
});
}, [ props ] ):
On the official react documentation it states: "Pass an inline callback and an array of dependencies. useCallback will return a memoized version of the callback that only changes if one of the dependencies has changed." In our case, the login function will update itself everytime [props]
changes, meaning when we get new props, we get a new login function.
Check out the official hook documentation for more information on how to use which hook.
You can even use useCallback
for all of your three functions!
const onChangePassword = useCallback( (event) => {
props.onChangePassword(event.target.value)
}, [props.onChangePassword]);
const onChangeEmail = useCallback( (event) => {
props.onChangeEmail(event.target.value)
}, [props.onChangeEmail]);
The onChangePassword
and onChangeEmail
callback functions will update and create new functions everytime your props.onChangePassword
and props.onChangeEmail
functions get updated from redux or higher-order-components.
Upvotes: 1