- useUnmountedRef: 用于判断是否首次渲染
import { useRef, useEffect } from 'react'
const useUnmountedRef = () => {
const unmountedRef = useRef(false)
useEffect(() => {
return () => {
unmountedRef.current = true
}
}, [])
return unmountedRef
}
export default useUnmountedRef
- 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
- useState的进阶版本,此hook中state的值只会被改变一次
import { useCallback, useRef, useState } from 'react'
export default function useStateOnce(initValue: T): [T, (newValue: T) => void] {
const updatedRef = useRef(false)
const [value, setState] = useState(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(cb: () => void, value: T) {
const prevValueRef = useRef(null)
useEffect(() => {
if (prevValueRef.current !== null && prevValueRef.current !== value) {
cb()
}
prevValueRef.current = value
}, [value])
}
- 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(null)
const [loading, setLoading] = useSafeState(false)
const [error, setError] = useSafeState(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()
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(
{content}
{onCancel && !hideCancelButton && (
{cancelLabel || t('button.cancel')}
)}
{onConfirm && {confirmLabel || t('button.confirm')} }
,
div
)
},
[containerRef, t]
)
return openModal
}