From 8606af3616350ef16ba7ff72e03350646406703e Mon Sep 17 00:00:00 2001 From: GyDi Date: Fri, 25 Feb 2022 01:21:13 +0800 Subject: [PATCH] feat: guard state supports debounce guard --- src/components/setting/guard-state.tsx | 79 ++++++++++++++++++-------- 1 file changed, 54 insertions(+), 25 deletions(-) diff --git a/src/components/setting/guard-state.tsx b/src/components/setting/guard-state.tsx index 9b15aa9..7e4f0d0 100644 --- a/src/components/setting/guard-state.tsx +++ b/src/components/setting/guard-state.tsx @@ -5,6 +5,7 @@ interface Props { value?: Value; valueProps?: string; onChangeProps?: string; + waitTime?: number; onChange?: (value: Value) => void; onFormat?: (...args: any[]) => Value; onGuard?: (value: Value, oldValue: Value) => Promise; @@ -18,6 +19,7 @@ function GuardState(props: Props) { children, valueProps = "value", onChangeProps = "onChange", + waitTime = 0, // debounce wait time default 0 onGuard = noop, onCatch = noop, onChange = noop, @@ -25,34 +27,61 @@ function GuardState(props: Props) { } = props; const lockRef = useRef(false); + const saveRef = useRef(value); + const lastRef = useRef(0); + const timeRef = useRef(); - if (isValidElement(children)) { - const childProps = { ...children.props }; - - childProps[valueProps] = value; - childProps[onChangeProps] = async (...args: any[]) => { - // 多次操作无效 - if (lockRef.current) return; - - lockRef.current = true; - const oldValue = value; - - try { - const newValue = (onFormat as any)(...args); - // 先在ui上响应操作 - onChange(newValue); - await onGuard(newValue, oldValue!); - } catch (err: any) { - // 状态回退 - onChange(oldValue!); - onCatch(err); - } - lockRef.current = false; - }; - return cloneElement(children, childProps); + if (!isValidElement(children)) { + return children as any; } - return children as any; + const childProps = { ...children.props }; + + childProps[valueProps] = value; + childProps[onChangeProps] = async (...args: any[]) => { + // 多次操作无效 + if (lockRef.current) return; + + lockRef.current = true; + + try { + const newValue = (onFormat as any)(...args); + // 先在ui上响应操作 + onChange(newValue); + + const now = Date.now(); + + // save the old value + if (waitTime <= 0 || now - lastRef.current >= waitTime) { + saveRef.current = value; + } + + lastRef.current = now; + + if (waitTime <= 0) { + await onGuard(newValue, value!); + } else { + // debounce guard + clearTimeout(timeRef.current); + + timeRef.current = setTimeout(async () => { + try { + await onGuard(newValue, saveRef.current!); + } catch (err: any) { + // 状态回退 + onChange(saveRef.current!); + onCatch(err); + } + }, waitTime); + } + } catch (err: any) { + // 状态回退 + onChange(saveRef.current!); + onCatch(err); + } + lockRef.current = false; + }; + return cloneElement(children, childProps); } export default GuardState;