[我已经阅读了很多关于using Accounts.onEmailVerificationLink
和Accounts.verifyEmail
的SO帖子,但是我还没有找到似乎可以解释如何从React客户端调用它们的帖子。
我已经设置了React Router,以将电子邮件验证链接上的点击路由到名为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电子邮件验证链接的正确方法是什么?
好吧,我不使用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
}