如何使用 next.js 重设密码表单路由
How to make a reset password form route with next.js
请参阅下面的编辑。
我在项目中遇到重设密码问题。我可以使用 link 向用户发送一封电子邮件,用于使用散列令牌和内部用户 ID 重置密码。
99% 的代码已经完成(后端和前端),唯一的问题是我无法在客户端获取散列令牌和 id 以调用正确的 API 端点,因此向用户显示用于重置密码的表单,并具有检查令牌、到期日期等的逻辑。
我没有使用 react-router-dom
(尽管我试图只在这条路线上使用它,但无论如何我都无法让它工作)。
基本上我发给用户的link是这个:
`http://localhost:3000/reset-password-form/${hashedResetToken}/${user._id}`
我的路线是这样的:
router.patch('/reset-password-form/:resetToken/:userId', shopController.resetPasswordPage);
现在,我尝试像这样将 react-router-dom 的功能添加到页面文件夹内的 reset-password-form.js 文件中,如下所示:
import React from 'react';
import ResetPasswordPage from '../components/ResetPasswordPage';
import { BrowserRouter as Router, Switch, Route} from 'react-router-dom';
const resetPasswordPage = () => {
return (
<>
<Router>
<Switch>
<Route exact path="/reset-password-form/:resetToken/:userId" component={ResetPasswordPage} />
</Switch>
</Router>
<ResetPasswordPage />
</>
)
}
export default resetPasswordPage;
而且,问题是我无法调用正确的 API 端点,因为我无法获得所需的参数。组件看起来像这样(它只是几行代码,而不是整个组件):
fetchData = e => {
e.preventDefault();
const resetToken = this.props.match.params.resetToken;
const userId = this.props.match.params.userId;
fetch(`http://localhost:8090/reset-password-form/${resetToken}/${userId}`, {
所以现在,如果我点击 link,我会收到 404 页面未找到。
如何在客户端获取这些参数?
编辑:
所以现在我按照建议使用 next/router
。
首先,我注意到如果令牌在 next/router
中使用 /
进行哈希处理,则无法读取令牌,它会给我一个 404 页面(可能是因为它认为有超过 2 个参数?)。我尝试在没有 /
的情况下调整路线,但没有成功。
出于调试目的,我的 reset-password-form/[resetToken]/[userId].js
进入页面文件夹如下所示:
const resetPasswordPage = () => {
const router = useRouter();
return (
<>
<p>user id: {router.query.userId}</p>
<p>token: {router.query.resetToken}</p>
</>
)
}
这给了我散列令牌(只有当它生成时没有内部 /
否则我会得到一个 404 页面)和 userId
.
调试后,我删除了 2 个 p
标签,并将 ResetPasswordPage
组件传递到 return 中,将我需要的参数作为道具传递并像这样获取它们( ResetPasswordPage
分量):
fetchData = e => {
e.preventDefault();
const resetToken = this.props.resetToken;
const userId = this.props.userId;
fetch(`http://localhost:8090/reset-password-form/${resetToken}/${userId}`, {
但如果我这样做,我会得到 Error: React.Children.only expected to receive a single React element child
。
如果我从 ResetPasswordPage
组件中删除其他 2 个子项,则会呈现我想要的页面(再次仅当生成令牌时没有 /
)。有什么方法可以渲染其他 2 个子项(我在 3 个组件之间有 <> > 标签)?这些对于页面的工作很重要(它们显示导航 link 和 error/success 消息)。
如果使用 /
对令牌进行哈希处理,用户将获得 404 页面,我该如何避免这一事实?
编辑 2.0
ResetPasswordPage
组件的完整代码:
import React, { Component } from 'react';
import Link from 'next/link';
import Form from '../components/styles/Form';
import Logo from '../components/styles/Logo';
import MessageStyles from '../components/styles/MessageStyles';
class ResetPasswordPage extends Component {
state = {
loading: false,
message: null,
password: '',
confirmPassword: '',
}
handleChange = e => {
this.setState({ [e.target.name]: e.target.value });
}
fetchData = e => {
e.preventDefault();
const resetToken = this.props.resetToken;
const userId = this.props.userId;
fetch(`http://localhost:8090/reset-password-form/${resetToken}/${userId}`, {
method: 'PATCH',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
credentials: 'include',
body: JSON.stringify({
password: this.state.password,
confirmPassword: this.state.confirmPassword,
})
})
.then(res => {
return res.json();
})
.then(resData => {
console.log(resData);
})
.then(() => {
setTimeout(() => {
window.location.replace('/auth/login');
}, 3000);
})
.catch(err => console.log(err))
}
render() {
return (
<>
<Logo> // by removing only the logo component with the link inside I solved the issue of Error: React.Children.only expected to receive a single React element child
<Link href="/shop" />
</Logo>
<MessageStyles><p id="message-test">{this.state.message}</p></MessageStyles>
<Form onSubmit={this.fetchData}>
<fieldset aria-busy={this.state.loading} disabled={this.state.loading}>
<h1>Chang{this.state.loading ? 'ing' : 'e'} Your Password</h1>
<label htmlFor="password">
<input
name="password"
type="password"
onChange={this.handleChange}
value={this.state.password}
className={this.state.password.length < 5 ? 'invalid' : '' }
/>
</label>
<label htmlFor="confirm password">
<input
name="confirmPassword"
type="password"
onChange={this.handleChange}
value={this.state.confirmPassword}
className={this.state.password !== this.state.confirmPassword ? 'invalid' : '' }
/>
</label>
<button>Chang{this.state.loading ? 'ing' : 'e'} Your Password</button>
</fieldset>
</Form>
</>
)
}
}
export default ResetPasswordPage;
因此,如果我删除 Logo
并且 MessageStyle
页面得到呈现。
Tms 发给我这个 link,他说你遇到了这个问题。我不是专业人士,但尝试从 Route 组件中删除“exact”。由于它是动态路径,因此可能是触发问题的原因。
我记不太清了,但你可能也不需要自闭 <ResetPasswordPage />
。你已经在路线中通过了它。(我想我也有类似的问题)
所以为了解决这个问题,我做了以下事情:
将文件 reset-password-form.js 重命名为这样的页面文件夹“reset-password-form/[resetToken]/[userId].js”。
reset-password-form/[resetToken]/[userId].js 看起来像这样:
import React from 'react';
import { useRouter } from 'next/router';
import ResetPasswordPage from '../../../components/ResetPasswordPage';
const resetPasswordPage = () => {
const router = useRouter();
return (
<ResetPasswordPage userId={router.query.userId} resetToken={router.query.resetToken} />
)
}
export default resetPasswordPage;
在 ResetPasswordPage 中,我通过像这样从 props 获取我需要的参数:
resetToken = this.props.resetToken;
userId = this.props.userId;
对于令牌中的 /,您需要 encode/decode 令牌 encodeURIComponent 和 decodeURIComponent
我正在回答你关于 /
问题的问题,因为你在一个 post.
中有多个编辑和多个问题
您可以使用 encodeURIComponent 对包含“/”的标记进行编码。
const token = `token1with/init`
console.log(`token`, token)
console.log(`encodeUri`, encodeURIComponent(token))
您应该在使用电子邮件发送之前对令牌进行编码。
请参阅下面的编辑。
我在项目中遇到重设密码问题。我可以使用 link 向用户发送一封电子邮件,用于使用散列令牌和内部用户 ID 重置密码。
99% 的代码已经完成(后端和前端),唯一的问题是我无法在客户端获取散列令牌和 id 以调用正确的 API 端点,因此向用户显示用于重置密码的表单,并具有检查令牌、到期日期等的逻辑。
我没有使用 react-router-dom
(尽管我试图只在这条路线上使用它,但无论如何我都无法让它工作)。
基本上我发给用户的link是这个:
`http://localhost:3000/reset-password-form/${hashedResetToken}/${user._id}`
我的路线是这样的:
router.patch('/reset-password-form/:resetToken/:userId', shopController.resetPasswordPage);
现在,我尝试像这样将 react-router-dom 的功能添加到页面文件夹内的 reset-password-form.js 文件中,如下所示:
import React from 'react';
import ResetPasswordPage from '../components/ResetPasswordPage';
import { BrowserRouter as Router, Switch, Route} from 'react-router-dom';
const resetPasswordPage = () => {
return (
<>
<Router>
<Switch>
<Route exact path="/reset-password-form/:resetToken/:userId" component={ResetPasswordPage} />
</Switch>
</Router>
<ResetPasswordPage />
</>
)
}
export default resetPasswordPage;
而且,问题是我无法调用正确的 API 端点,因为我无法获得所需的参数。组件看起来像这样(它只是几行代码,而不是整个组件):
fetchData = e => {
e.preventDefault();
const resetToken = this.props.match.params.resetToken;
const userId = this.props.match.params.userId;
fetch(`http://localhost:8090/reset-password-form/${resetToken}/${userId}`, {
所以现在,如果我点击 link,我会收到 404 页面未找到。
如何在客户端获取这些参数?
编辑:
所以现在我按照建议使用 next/router
。
首先,我注意到如果令牌在 next/router
中使用 /
进行哈希处理,则无法读取令牌,它会给我一个 404 页面(可能是因为它认为有超过 2 个参数?)。我尝试在没有 /
的情况下调整路线,但没有成功。
出于调试目的,我的 reset-password-form/[resetToken]/[userId].js
进入页面文件夹如下所示:
const resetPasswordPage = () => {
const router = useRouter();
return (
<>
<p>user id: {router.query.userId}</p>
<p>token: {router.query.resetToken}</p>
</>
)
}
这给了我散列令牌(只有当它生成时没有内部 /
否则我会得到一个 404 页面)和 userId
.
调试后,我删除了 2 个 p
标签,并将 ResetPasswordPage
组件传递到 return 中,将我需要的参数作为道具传递并像这样获取它们( ResetPasswordPage
分量):
fetchData = e => {
e.preventDefault();
const resetToken = this.props.resetToken;
const userId = this.props.userId;
fetch(`http://localhost:8090/reset-password-form/${resetToken}/${userId}`, {
但如果我这样做,我会得到 Error: React.Children.only expected to receive a single React element child
。
如果我从 ResetPasswordPage
组件中删除其他 2 个子项,则会呈现我想要的页面(再次仅当生成令牌时没有 /
)。有什么方法可以渲染其他 2 个子项(我在 3 个组件之间有 <> > 标签)?这些对于页面的工作很重要(它们显示导航 link 和 error/success 消息)。
如果使用 /
对令牌进行哈希处理,用户将获得 404 页面,我该如何避免这一事实?
编辑 2.0
ResetPasswordPage
组件的完整代码:
import React, { Component } from 'react';
import Link from 'next/link';
import Form from '../components/styles/Form';
import Logo from '../components/styles/Logo';
import MessageStyles from '../components/styles/MessageStyles';
class ResetPasswordPage extends Component {
state = {
loading: false,
message: null,
password: '',
confirmPassword: '',
}
handleChange = e => {
this.setState({ [e.target.name]: e.target.value });
}
fetchData = e => {
e.preventDefault();
const resetToken = this.props.resetToken;
const userId = this.props.userId;
fetch(`http://localhost:8090/reset-password-form/${resetToken}/${userId}`, {
method: 'PATCH',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
credentials: 'include',
body: JSON.stringify({
password: this.state.password,
confirmPassword: this.state.confirmPassword,
})
})
.then(res => {
return res.json();
})
.then(resData => {
console.log(resData);
})
.then(() => {
setTimeout(() => {
window.location.replace('/auth/login');
}, 3000);
})
.catch(err => console.log(err))
}
render() {
return (
<>
<Logo> // by removing only the logo component with the link inside I solved the issue of Error: React.Children.only expected to receive a single React element child
<Link href="/shop" />
</Logo>
<MessageStyles><p id="message-test">{this.state.message}</p></MessageStyles>
<Form onSubmit={this.fetchData}>
<fieldset aria-busy={this.state.loading} disabled={this.state.loading}>
<h1>Chang{this.state.loading ? 'ing' : 'e'} Your Password</h1>
<label htmlFor="password">
<input
name="password"
type="password"
onChange={this.handleChange}
value={this.state.password}
className={this.state.password.length < 5 ? 'invalid' : '' }
/>
</label>
<label htmlFor="confirm password">
<input
name="confirmPassword"
type="password"
onChange={this.handleChange}
value={this.state.confirmPassword}
className={this.state.password !== this.state.confirmPassword ? 'invalid' : '' }
/>
</label>
<button>Chang{this.state.loading ? 'ing' : 'e'} Your Password</button>
</fieldset>
</Form>
</>
)
}
}
export default ResetPasswordPage;
因此,如果我删除 Logo
并且 MessageStyle
页面得到呈现。
Tms 发给我这个 link,他说你遇到了这个问题。我不是专业人士,但尝试从 Route 组件中删除“exact”。由于它是动态路径,因此可能是触发问题的原因。
我记不太清了,但你可能也不需要自闭 <ResetPasswordPage />
。你已经在路线中通过了它。(我想我也有类似的问题)
所以为了解决这个问题,我做了以下事情:
将文件 reset-password-form.js 重命名为这样的页面文件夹“reset-password-form/[resetToken]/[userId].js”。
reset-password-form/[resetToken]/[userId].js 看起来像这样:
import React from 'react';
import { useRouter } from 'next/router';
import ResetPasswordPage from '../../../components/ResetPasswordPage';
const resetPasswordPage = () => {
const router = useRouter();
return (
<ResetPasswordPage userId={router.query.userId} resetToken={router.query.resetToken} />
)
}
export default resetPasswordPage;
在 ResetPasswordPage 中,我通过像这样从 props 获取我需要的参数:
resetToken = this.props.resetToken;
userId = this.props.userId;
对于令牌中的 /,您需要 encode/decode 令牌 encodeURIComponent 和 decodeURIComponent
我正在回答你关于 /
问题的问题,因为你在一个 post.
您可以使用 encodeURIComponent 对包含“/”的标记进行编码。
const token = `token1with/init`
console.log(`token`, token)
console.log(`encodeUri`, encodeURIComponent(token))
您应该在使用电子邮件发送之前对令牌进行编码。