react custom hook
useBoolean
import {useState, useCallback} from 'react';
type BooleanHook = [boolean, () => void, () => void];
const useBoolean = (initialValue: boolean = false): BooleanHook => {
const [value, setValue] = useState(initialValue);
const on = useCallback(
() => setValue(true),
[]
);
const off = useCallback(
() => setValue(false),
[]
);
return [value, on, off];
};
export default useBoolean;
useQuery
import {useMemo} from 'react';
import {useLocation} from 'react-router-dom';
import * as queryString from 'query-string';
type ParsedQuery = queryString.ParsedQuery;
export const useQuery = <T extends ParsedQuery>(): T => {
const {search} = useLocation();
const query = useMemo(
() => queryString.parse(search, {arrayFormat: 'bracket'}),
[search]
);
return query as T;
};
export default useQuery;
useCountDown one
import {useCallback, useEffect, useState} from 'react';
import moment from 'moment';
export interface Countdown {
deadline: string;
format?: 'YYYY-MM-DD HH:mm:ss' | string;
}
export type Remains = Record<'day' | 'hour' | 'minute' | 'second', number>;
const useCountdown = ({
deadline,
format = 'YYYY-MM-DD HH:mm:ss',
}: ICountdown): Remains => {
const [{current, updater}, setCurrent] = useState({
current: moment(),
updater: 0,
});
const [remains, setRemains] = useState<Remains>({
day: 0,
hour: 0,
minute: 0,
second: 0,
});
useEffect(
() => {
const timer = window.setInterval(() => {
current.isSameOrAfter(moment(deadline, format))
? clearInterval(timer)
: setCurrent(prev => ({
current: prev.current.add(0.5, 's'),
updater: prev.updater + 1,
}));
}, 1000);
return () => clearInterval(timer);
},
[deadline]
);
const formatTime = useCallback(
time => (
time < 10 ? `0${time}` : time
),
[]
);
useEffect(
() => {
let millisec = moment(deadline, format).valueOf() - current.valueOf();
millisec = millisec >= 0 ? millisec : 0;
setRemains({
day: formatTime(Math.floor(millisec / (1000 * 60 * 60 * 24))),
hour: formatTime(Math.floor((millisec / (1000 * 60 * 60)) % 24)),
minute: formatTime(Math.floor((millisec / (1000 * 60)) % 60)),
second: formatTime(Math.round((millisec / 1000) % 60)),
});
},
[updater]
);
return remains;
};
export default useCountdown;
const deadline = useMemo(
() =>
moment(data?.ctime * 1000).add(5, 'm').format('YYYY-MM-DD HH:mm:ss'),
[data?.ctime]
);
const {hour, minute, second} = useCountdown({
deadline,
});
useCountDown two
import React , {useState, useEffect, useCallback} from "react";
const bw = (n: number) => {
return n > 9 ? n :'0' + n;
};
interface CounrDown {
expried: boolean,
timeStr: string,
days: number,
hours: number,
minutes: number,
seconds: number,
}
const useCountDown = (targetTime: string | number) => {
const [timeDiff, setTimeDiff] = useState<CounrDown>({
expried: false,
timeStr: '',
days: 0,
hours: 0,
minutes: 0,
seconds: 0,
});
const time = useCallback(() => {
let future = + new Date(targetTime)
let nowDate = + new Date()
let s = parseInt((future-nowDate) / 1000 + '')
let d = parseInt(s / 86400 + '')
let h = parseInt((s % 86400) / 3600 + '')
let ms = parseInt((s % 3600) / 60 + '')
let sc = parseInt(s % 60 + '')
const timeStr = `距离${targetTime}还剩:${bw(d)}天-${bw(h)}小时-${bw(ms)}分钟-${bw(sc)}秒`;
const expried = s > 0 ? false : true;
setTimeout(() => {
setTimeDiff(state => {
return {
...state,
timeStr,
expried,
days: d < 0 ? - d : d,
hours: h < 0 ? - h : h,
minutes: ms < 0 ? - ms : ms,
seconds: sc < 0 ? - sc : sc,
}
});
}, 1000)
},
[timeDiff]
);
useEffect(() => {
time();
}, [time]);
return timeDiff;
}
export default useCountDown;
const result = useCountDown(targetTime);
useInterval
import React ,{useRef, useEffect, MutableRefObject} from "react";
const useInterVal = (callback: () => void, delaty: number | null) => {
const savedCallback: MutableRefObject<any>= useRef();
useEffect(() => {
savedCallback.current = callback;
});
useEffect(() => {
const tick = () => {
savedCallback.current();
};
if (delaty !== null) {
const id = setInterval(tick, delaty);
return () => clearInterval(id);
}
}, [delaty]);
};
export default useInterVal;
useCountDown for two edit
import React , {useState} from "react";
import useInterVal from "./useInterval";
const bw = (n: number) => {
return n > 9 ? n :'0' + n;
};
interface CounrDown {
expried: boolean,
timeStr: string,
days: number,
hours: number,
minutes: number,
seconds: number,
}
const useCountDown = (targetTime: string | number) => {
const [timeDiff, setTimeDiff] = useState<CounrDown>({
expried: false,
timeStr: '',
days: 0,
hours: 0,
minutes: 0,
seconds: 0,
});
const time = () => {
let future = + new Date(targetTime)
let nowDate = + new Date()
let s = parseInt((future-nowDate) / 1000 + '')
let d = parseInt(s / 86400 + '')
let h = parseInt((s % 86400) / 3600 + '')
let ms = parseInt((s % 3600) / 60 + '')
let sc = parseInt(s % 60 + '')
const timeStr = `距离${targetTime}还剩:${bw(d)}天-${bw(h)}小时-${bw(ms)}分钟-${bw(sc)}秒`;
const expried = s > 0 ? false : true;
const days = d < 0 ? - d : d;
const hours = h < 0 ? - h : h;
const minutes = ms < 0 ? - ms : ms;
const seconds = sc < 0 ? - sc : sc;
setTimeDiff(state => {
state.timeStr = timeStr;
state.expried = expried;
state.days = days;
state.hours = hours;
state.minutes = minutes;
state.seconds = seconds;
return state;
});
};
useInterVal(() => {
time()
}, 1000);
return timeDiff;
}
export default useCountDown;
useSyncCallback (在回调中获得useState最新的值)
import {useState, useEffect, useCallback} from 'react';
const useSyncCallback = <T>(callback: (value?: T) => void) => {
const [proxyState, setProxyState] = useState({current: false});
const [parameters, setParameters] = useState<T>();
const Func = useCallback((val?: T) => {
setParameters(val);
setProxyState({current: true});
}, []);
useEffect(() => {
if (proxyState.current === true) {
setProxyState({current: false});
}
}, [proxyState]);
useEffect(() => {
proxyState.current && callback(parameters);
});
return Func;
};
export default useSyncCallback;
const getSyncHot = useSyncCallback(() => {
const belongList = searchData.status || searchData.status === 0 ? searchData.status : '';
const status = searchData.time || searchData.time === 0 ? searchData.time : '';
const sendParams = {
belongList,
content: searchData.content,
page: 1,
pageOrder: true,
pageSize: 10,
pageSort: 'create_time',
regionCode: searchData.typeKeywords.regionCode || '',
status,
};
(async () => {
...
})();
});
useStateSync (同步state hook)
import { useRef, useState, useEffect } from 'react';
enum NUMS {
ZERO,
ONE,
}
type SyncFunc<K> = (value: K) => void | undefined;
type DispatchFunc<K> = (newData: K | ((prev: K) => K), callF?: SyncFunc<K>) => Promise<K>;
type ReturnArray<K> = [K, DispatchFunc<K>];
const useStateSync = <T>(initValue: T) => {
const ref = useRef<number>(NUMS.ZERO);
const callFRef = useRef<(val: T) => void>();
const setFuncRef = useRef<DispatchFunc<T>>();
const [state, setState] = useState<T>(initValue);
const prevValue = useRef<T>(initValue);
if (!ref.current) {
ref.current = NUMS.ONE;
setFuncRef.current = (newData: T | ((prev: T) => T), callF?: SyncFunc<T>) => {
callFRef.current = callF;
if (newData instanceof Function) {
setState((prev) => {
prevValue.current = prev;
return newData(prev);
});
return Promise.resolve(prevValue.current);
}
setState(newData);
return Promise.resolve(newData);
};
}
useEffect(() => {
callFRef.current?.(state);
}, [state]);
return [state, setFuncRef.current] as ReturnArray<T>;
};
export default useStateSync;
const [commonNum, setCommonNum] = useStateSync<
{
key: number;
fileList: unknown[];
}[]
>(commonNumData);
const customRequest = ({ file, onSuccess }: any, index: number) => {
setTimeout(() => {
onSuccess('success');
setCommonNum(
(prevCommonNum) => upDateFileList(prevCommonNum, index, file),
(newValue) => console.log('newValue', newValue),
).then((res) => console.log('reeessss', res));
console.log('立即查看', commonNum);
}, 1000);
};
const [count, setCount] = useStateSync<number>(1);
const handelClick = () => {
setCount(count + 1).then((newValue: number) => {
console.warn('.thenSyncState', newValue);
});
console.warn('noSync', count);
};
useMount ( 只执行一次)
import { useEffect } from "react";
export const useMount = (callBack: () => void) => {
useEffect(() => {
callBack();
}, []);
};
useDebounce (对值进行防抖)
import { useEffect, useState } from "react";
export const useDebounce = <V>(value: V, delay: number) => {
const [debouncedValue, setDebouncedValue] = useState<V>(value);
useEffect(() => {
let timeout = setTimeout(() => setDebouncedValue(value), delay);
return () => clearTimeout(timeout);
}, [delay, value]);
return debouncedValue;
};
...
..
const [param, setParam] = useState({
name: "",
personId: "",
});
const debouncedParam = useDebounce(param, 500);
useEffect(() => {
fetch(`${api}/projects?${qs.stringify(cleanObject(debouncedParam))}`).then(async (response) => {
if (response.ok) {
setList(await response.json());
}
});
}, [debouncedParam]);
useMountRef 判断组件处于挂载还是卸载状态
import { useEffect, useRef } from "react"
export const useMountRef = () => {
const mountedRef = useRef(false);
useEffect(() => {
mountedRef.current = true;
return () => {
mountedRef.current = false;
}
});
return mountedRef;
};