记录一些工作中的常用的自定义hook

  1. useUnmountedRef: 用于判断是否首次渲染
import { useRef, useEffect } from 'react'

const useUnmountedRef = () => {
  const unmountedRef = useRef(false)
  useEffect(() => {
    return () => {
      unmountedRef.current = true
    }
  }, [])
  return unmountedRef
}

export default useUnmountedRef
  1. useState的进阶版本,当首次渲染的时候不改变state中的值
import { useState, Dispatch, SetStateAction, useCallback } from 'react'
import useUnmountedRef from './useUnmountedRef'

function useSafeState(initialState?: any) {
  const unmountedRef = useUnmountedRef()
  const [state, setState] = useState(initialState)
  const setCurrentState = useCallback((currentState: any) => {
    /** don't invoke setState if component is unmounted */
    if (unmountedRef.current) return
    setState(currentState)
  }, [])

  return [state, setCurrentState] as const
}

export default useSafeState

  1. useState的进阶版本,此hook中state的值只会被改变一次
import { useCallback, useRef, useState } from 'react'

export default function useStateOnce<T = any>(initValue: T): [T, (newValue: T) => void] {
  const updatedRef = useRef<boolean>(false)
  const [value, setState] = useState<T>(initValue)
  const setStateOnce = useCallback((newValue: T) => {
    if (!updatedRef.current) {
      updatedRef.current = true
      setState(newValue)
    }
  }, [])

  return [value, setStateOnce]
}

4.useValueChange:此hook业务中非常常用,传入两个参数callback以及value,该hook依赖value,如果value从无到有或者值发生改变则调用callback函数

import { useRef, useEffect } from 'react'

export default function useValueChange<T>(cb: () => void, value: T) {
  const prevValueRef = useRef<T | null>(null)
  useEffect(() => {
    if (prevValueRef.current !== null && prevValueRef.current !== value) {
      cb()
    }
    prevValueRef.current = value
  }, [value])
}

  1. useAsync:一个运行函数的状态机,给予一个异步函数loading,error等状态
import { useRef, useCallback } from 'react'

import useSafeState from './useSafeState'

export default function useAsync(func: (...args: any[]) => any, handleError?: (e: any) => any) {
  const [data, setData] = useSafeState<any>(null)
  const [loading, setLoading] = useSafeState<boolean>(false)
  const [error, setError] = useSafeState<null | Error>(null)
  const funcRef = useRef(func)
  funcRef.current = func
  const handleErrorRef = useRef(handleError)
  handleErrorRef.current = handleError

  const run = useCallback(async (...params: any[]) => {
    setError(null)
    setLoading(true)

    try {
      const data = await funcRef.current(...params)
      setData(data)
      return data
    } catch (e) {
      setError(e as Error)
      if (handleErrorRef.current) {
        handleErrorRef.current(e)
      }
    } finally {
      setLoading(false)
    }
  }, [])

  const reset = useCallback(() => {
    setData(null)
    setLoading(false)
    setError(null)
  }, [])

  return {
    run,
    loading,
    error,
    data,
    reset
  }
}

6.useConfirmDialog:一个用于自定义弹出框的hook,该hook只会返回true or false

export default function useConfirmDialog() {
  const containerRef = useRef<HTMLElement>()
  const { t } = useTranslation('common') //此为i-18n的国际化hook,可去除

  const openModal = useCallback(
    ({
      title,
      content,
      onConfirm,
      onCancel,
      confirmLabel,
      cancelLabel,
      hideCancelButton = false
    }: IConfirmDialogConfigs) => {
      const div = document.createElement('div')
      div.setAttribute('id', 'confirm-modal-container')
      document.body.appendChild(div)

      const closeModal = () => {
        const unmountResult = ReactDOM.unmountComponentAtNode(div)
        if (unmountResult && div.parentNode) {
          div.parentNode.removeChild(div)
        }
      }

      const handleConfirm = async () => {
        await onConfirm(closeModal)
      }
      const handleCancel = async () => {
        closeModal()
        if (onCancel) {
          onCancel()
        }
      }
      containerRef.current = div
      ReactDOM.render(
        <Modal
          title={title || ''}
          hideTitle={!title}
          isOpen={true}
          onClose={onCancel ? handleCancel : handleConfirm}
          containerRef={containerRef}
        >
          {content}
          <ModalContentWrap>
            {onCancel && !hideCancelButton && (
              <StyledButton secondary onClick={handleCancel}>
                {cancelLabel || t('button.cancel')}
              </StyledButton>
            )}
            {onConfirm && <StyledButton onClick={handleConfirm}>{confirmLabel || t('button.confirm')}</StyledButton>}
          </ModalContentWrap>
        </Modal>,
        div
      )
    },
    [containerRef, t]
  )
  return openModal
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,122评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,070评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,491评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,636评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,676评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,541评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,292评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,211评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,655评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,846评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,965评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,684评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,295评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,894评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,012评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,126评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,914评论 2 355

推荐阅读更多精彩内容