Meteor:从 React 客户端调用 verifyEmail?

Meteor: Calling verifyEmail From React Client?

我已经阅读了很多关于 using Accounts.onEmailVerificationLinkAccounts.verifyEmail 的 SO 帖子,但我还没有找到一个似乎解释了如何从 React 客户端调用它们的帖子。

我将 React Router 设置为将对电子邮件验证 link 的点击路由到名为 ConfirmEmail 的 React 组件。路由器将验证令牌捕获到 props.match.params.emailValidationToken.

ConfirmEmail 组件如下所示:

import React, {useEffect, useRef, useState} from "react";

function ConfirmEmail(props) {
    const {client, match, history} = props;

    const doSetUp = useRef(true);
    const emailVerificationToken = useRef(props.match.params.emailValidationToken);

    if (doSetUp.current){
        doSetUp.current = false;
        debugger;
        Accounts.onEmailVerificationLink(function(token, done) {
            Accounts.verifyEmail(emailVerificationToken.current, function(error) {
                debugger;
                if (error) {
                    console.log(error)
                } else {
                    console.log(success)
                }
            })
        });
    }


    return (
        <p>Your email address has been verified.</p>
    )
}

export default ConfirmEmail;

我尝试了几种不同的方法,但还没有找到有效的方法。

从 React 客户端处理点击 Meteor 电子邮件验证 link 的正确方法是什么?

好吧,我不使用 React Hooks,但我想你会发现很容易将它移植到你的口味。

这一切都需要在 componentDidMount() 中发生。这确保您可以使用令牌,并且您只 运行 此过程一次。 在下面的代码中,toastr 是客户端的 UI 通知系统。


import React, { Component } from 'react'
import { connect } from 'react-redux' // if you use redux, here it is used to get the user slug from props.
import { Link } from 'react-router-dom'
import PropTypes from 'prop-types' // not relevant
import { Accounts } from 'meteor/accounts-base'
import { toastr } from 'react-redux-toastr' // not relevant
import { TiWarningOutline, TiThumbsOk } from '../../components/shared/Icons/icons' // not relevant

class ConfirmEmail extends Component {
  constructor (props) {
    super(props)
    this.state = {
      linkExpired: false,
      logged: true // I need to know if the user is logged in before I test the token
    }
  }

  componentDidMount () {
    const { match, history, slug } = this.props
    const token = match.params.token

    // If the user is not logged in I cannot test the token against an email.
    if (!slug) {
      this.setState({ logged: false })
      return
    }

    Accounts.verifyEmail(token, err => {
      if (err && err.reason === 'Verify email link expired') {
        this.setState({ linkExpired: true })
      }
      // Inform the user what went wrong
      if (err) {
        toastr.light('Could not verify email!', `Error: ${err.reason}`, { timeOut: 2000, icon: (<TiWarningOutline style={{ fontSize: 42, color: 'red' }} />) })
      } else {
        // Confirm to user and move on to where you want to direct the user first or ask the user to close the window...or else
        toastr.light('You\'ve Successfully Confirmed Your Email Address!', { timeOut: 4000, icon: (<TiThumbsOk style={{ fontSize: 42, color: 'rgb(74, 181, 137)' }} />) })
        history.push('/feeds')
      }
    })
  }

  render () {
    const { linkExpired, logged } = this.state
    return (
      <div style={{ textAlign: 'center', paddingTop: 80 }}>
        {logged
          ? <>
            {linkExpired
              ? <p>This link has expired.</p>
              : <>
                <img src={`${IMAGE_BANK}/images/6.svg`} style={{ width: 36 }} /> // this is a spinner
                <p>Awaiting confirmation ...</p>
              </>}
          </>
          : <>
            <p style={{ maxWidth: 360, margin: '0 auto' }}>
              In order to verify your email address you need to be authenticated. Please sign in and try the verification link from your email one more time.
            </p>
            <br />
            <Link to='/signin' className='btn btn-primary'>Sign In</Link>
          </>
        }
      </div>
    )
  }
}

// this block is relevant in Redux context. Just gets the slug (or some other way to check if the user is logged in.)
const mapStateToProps = state => {
  const currentUser = state.user.currentUser
  return {
    slug: currentUser?.slug
  }
}
export default connect(mapStateToProps, { })(ConfirmEmail)

// from here, not so relevant
ConfirmEmail.propTypes = {
  params: PropTypes.object
}