如何在 recaptcha 回调中访问更新的道具

How to access updated props in recaptcha callback

我正在尝试通过 React 和 Redux 使用集成在 firebase 身份验证中的 reCaptcha。

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="nombre@mail.com"
                           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);

问题是登录回调中的道具已经过时,并且不包含在 redux 存储中加载的电子邮件和密码,它只包含触发 useEffect 时可用的道具。 (我看到 console.log(props))

我不知道如何保留对更新道具的引用。我试过使用 useRef 挂钩并将其作为参数发送到登录名,但这也没有用。

我也试过使用电子邮件和密码道具作为 useEffect 依赖项,但这会多次触发 recaptcha 生成,而且效率非常低。

感谢您的帮助!

使用回调挂钩以高性能方式访问最新状态。

    const login = useCallback( () => {
        console.log(props)
        firebaseLogin(props.email, props.password).then(() => {
                ...
            }
        ).catch(function (error) {
            console.log(error);
            ...
        });
    }, [ props ] ):

在官方 React 文档中它指出:"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." 在我们的例子中,每次 [props] 更改时,登录功能都会自行更新,这意味着当我们获得新道具时,我们将获得一个新的登录功能。

查看官方 hook documentation 以获取有关如何使用 which hook 的更多信息。

您甚至可以将 useCallback 用于所有三个功能!

    const onChangePassword = useCallback( (event) => {
        props.onChangePassword(event.target.value)
    }, [props.onChangePassword]);

    const onChangeEmail = useCallback( (event) => {
        props.onChangeEmail(event.target.value)
    }, [props.onChangeEmail]);

每次从 redux 或高阶组件更新 props.onChangePasswordprops.onChangeEmail 函数时,onChangePasswordonChangeEmail 回调函数将更新并创建新函数。

似乎可以作为

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();
    }, []);

还有一个问题,但与本题无关