React Hooks 问题及解决

定时器的使用

因为闭包,定时器里无法直接修改 state 里的数据。

import React, { useEffect, useRef, useState } from 'react'
import { Modal } from 'antd'

let inter: null | NodeJS.Timeout = null


export default function QRCodeModal(props: propType) {
  const [time, setTime] = useState(60)

  // 倒计时
  if (time <= 0 && inter) {
    clearInterval(inter)
  }
  const startTime = () => {
    setTime(60)
    inter = setInterval(() => {
      setTime((time) => time - 1)
    }, 1000)
  }

  const modalProps = {
    maskClosable: false,
    visible: true,
    width: 1444,
    modalRender: () => {
      return (
        <Button
          className={styles.button}
          onClick={() => {
            startTime()
          }}
        >
          发送
        </Button>
      )
    },
  }
  return <Modal {...modalProps}></Modal>
}

useRef 第二次为 null

在第一次渲染的时候,ref 可以拿到 dom 的引用,但第二次就是 null 了。因为 ref 的值改变并不会触发二次渲染。为了解决这个问题,可以使用 useEffect。

import React, { useEffect, useRef, useState } from 'react'
import { Modal, Input, Button, message } from 'antd'
import styles from './styles.less'
import QRCode from 'qrcode'


export default function QRCodeModal(props) {
  const { url } = props
  const canvasRef = useRef<HTMLCanvasElement | null>(null)
  useEffect(() => {
    // 绘图
    console.log(canvasRef)
    if (url && canvasRef.current) {
      QRCode.toCanvas(
        canvasRef.current,
        url,
        {
          width: 140,
          margin: 0,
        },
        (err: unknown) => {
          console.log(err)
        },
      )
    }
  }, [canvasRef])


  const modalProps = {
    maskClosable: false,
    visible: true,
    width: 1444,
    modalRender: () => {
      return (
        <canvas
          className={styles.qrcode}
          ref={(el) => {
            canvasRef.current = el
          }}
        />
      )
    },
  }
  return <Modal {...modalProps}></Modal>
}