Meteor:从 React 客户端调用 verifyEmail?
Meteor: Calling verifyEmail From React Client?
我已经阅读了很多关于 using Accounts.onEmailVerificationLink
和 Accounts.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
}
我已经阅读了很多关于 using Accounts.onEmailVerificationLink
和 Accounts.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
}