![cd9ba04c69c091261989b14b7ef52ae2.png](https://i-blog.csdnimg.cn/blog_migrate/7fa230d3f9e72d3075b006271358dd9a.jpeg)
需求:我们现在有一个获取验证码的按钮,需要在点击后禁用,并且在按钮上显示倒计时60秒才可以进行第二次点击。 本篇文章通过对这个需求的八种实现方式来讨论在 react 中的逻辑复用的进化过程
代码例子放在了 codesandbox 上。
方案一 使用 setInterval
import React from 'react'
export default class LoadingButtonInterval extends React.Component {
state = {
loading: false,
btnText: '获取验证码',
totalSecond: 10
}
timer = null
componentWillUnmount() {
this.clear()
}
clear = () => {
clearInterval(this.timer)
this.setState({
loading: false,
totalSecond: 10
})
}
setTime = () => {
this.timer = setInterval(() => {
const {
totalSecond } = this.state
if (totalSecond <= 0) {
this.clear()
return
}
this.setState(() => ({
totalSecond: totalSecond - 1
}))
}, 1000)
}
onFetch = () => {
this.setState(() => ({
loading: true }))
const {
totalSecond } = this.state
this.setState(() => ({
totalSecond: totalSecond - 1
}))
this.setTime()
}
render() {
const {
loading, btnText, totalSecond } = this.state
return (
<button disabled={
loading} onClick={
this.onFetch}>
{
!loading ? btnText : `请等待${
totalSecond}秒..`}
</button>
)
}
}
方案二 使用 setTimeout
import React from 'react'
export default class LoadingButton extends React.Component {
state = {
loading: false,
btnText: '获取验证码',
totalSecond: 60
}
timer = null
componentWillUnmount() {
this.clear()
}
clear = () => {
clearTimeout(this.timer)
this.setState({
loading: false,
totalSecond: 60
})
}
setTime = () => {
const {
totalSecond } = this.state
if (totalSecond <= 0) {
this.clear()
return
}
this.setState({
totalSecond: totalSecond - 1
})
this.timer = setTimeout(() => {
this.setTime()
}, 1000)
}
onFetch = () => {
this.setState(() => ({
loading: true }))
this.setTime()
}
render() {
const {
loading, btnText, totalSecond } = this.state
return (
<button disabled={
loading} onClick={
this.onFetch}>
{
!loading ? btnText : `请等待${
totalSecond}秒..`}
</button>
)
}
}
我们可能很快就写出来两个这样的组件。使用 setTimeout 还是 setInterval 区别不是特别大。 但是我会更推荐 setTimeout 因为 万物皆递归(逃)
不过,又有更高的要求了。可以看到刚刚我们的获取验证码。如果说再有一个页面有相同的需求,只能将组件完全再拷贝一遍。这肯定不合适嘛。
那咋办嘛?
方案三 参数提取到 Props 1
import React from "react";
class LoadingButtonProps extends React.Component {
constructor(props) {
super(props);
this.initState = {
loading: false,
btnText: this.props.btnText || "获取验证码",
totalSecond: this.props.totalSecond || 60
};
this.state = {
...this.initState };
}
timer = null;
componentWillUnmount() {
this.clear();
}
clear = () => {
clearTimeout(this.timer);
this.setState({
...t