Reacthooks封装---倒计时

376 阅读1分钟

目标

能够在点击获取验证码时显示倒计时

装自定义hooks

hooks/useCountDown.ts

import { useEffect, useRef, useState } from 'react'

export default function useCountDown (initCount = 10, callBack = () => {}) {
  const timeId = useRef<{id:number}>({ id: 0 })
  const [count, setCount] = useState(initCount)

  const start = () => {
    setCount(initCount)
    timeId.current.id = window.setInterval(() => {
      setCount((count) => count - 1)
    }, 1000)
  }
  useEffect(() => {
    return () => {
      // console.log('..........')
      clearInterval(timeId.current.id)
    }
  }, [])

  useEffect(
    () => {
      // console.log(count, timeId.current)
      if (count === 0) {
        clearInterval(timeId.current.id)
        callBack()
      }
    },
    [count]
  )

  return { count, start }
}

使用自定义hooks

pages/Login/Login.tsx 中

+ import useCountDown from '@/hooks/useCountDown'
import { login, getCode } from '@/store/actions/login'
import { LoginForm } from '@/types/data'
import { Button, NavBar, Form, Input, List, Toast } from 'antd-mobile'
import { InputRef } from 'antd-mobile/es/components/input'
import { AxiosError } from 'axios'
import { useState, useRef } from 'react'

import { useDispatch } from 'react-redux'
import { useHistory } from 'react-router'

import styles from './index.module.scss'

const Login = () => {
+  const { count, start } = useCountDown(5, () => { setSentable(true) })
+  const [sendable, setSentable] = useState(true)
  const [form] = Form.useForm()
  const refMobile = useRef<InputRef>(null)
  const dispatch = useDispatch()
  const history = useHistory()
  const onFinish = async (value: LoginForm) => {
    try {
      await dispatch(login(value))
      // 登录成功提示
      Toast.show({
        content: '登录成功',
        duration: 600,
        afterClose: () => {
          // 返回首页
          history.push('/layout')
        }
      })
    } catch (err) {
      const error = err as AxiosError<{ message: string }>
      Toast.show({
        content: error.response?.data.message,
        duration: 1000
      })
    }
  }
  const onGetCode = () => {
    // 拿到手机号
    const mobile = form.getFieldValue('mobile')
    const errs = form.getFieldError('mobile')
    if (errs.length) {
      refMobile.current?.focus()
      return
    }
    // 发验证码
     dispatch(getCode(mobile))
    // 禁用按钮
+    setSentable(false)
    // 开始倒计时
+    start()
  }
  return (
    <div className={styles.root}>
      <NavBar />

      <div className="login-form">
        <h2 className="title">账号登录</h2>

        <Form form={form} initialValues={{ mobile: 13811111111 }} onFinish={onFinish}>
          <Form.Item

            name="mobile"
            className="login-item"
            rules={[
              { required: true, message: '必须输入手机号' },
              { pattern: /^1\d{10}$/, message: '手机号格式不对' }
            ]}>
            <Input ref={refMobile} placeholder="手机号" />
          </Form.Item>
          <List.Item
            className="login-code-extra"
            extra={

              <span
                className="code-extra"
       +         onClick={sendable ? onGetCode : undefined}
       +         >{sendable ? '发送验证码' : `${count}秒后重试`}
                </span>
              }>
            <Form.Item
              name="code"
              className="login-item"
              rules={[{ pattern: /^\d{6}$/, message: '必须输入6位数字的验证码' }]}>
              <Input placeholder="请输入验证码" autoComplete="off" />
            </Form.Item>
          </List.Item>

          <Form.Item noStyle>
            <Button
              block
              type="submit"
              color="primary"
              className="login-submit">
              提交
            </Button>
          </Form.Item>
        </Form>
      </div>
    </div>
  )
}
export default Login