|
@@ -5,6 +5,7 @@ interface Props<Value> {
|
|
|
value?: Value;
|
|
|
valueProps?: string;
|
|
|
onChangeProps?: string;
|
|
|
+ waitTime?: number;
|
|
|
onChange?: (value: Value) => void;
|
|
|
onFormat?: (...args: any[]) => Value;
|
|
|
onGuard?: (value: Value, oldValue: Value) => Promise<void>;
|
|
@@ -18,6 +19,7 @@ function GuardState<T>(props: Props<T>) {
|
|
|
children,
|
|
|
valueProps = "value",
|
|
|
onChangeProps = "onChange",
|
|
|
+ waitTime = 0, // debounce wait time default 0
|
|
|
onGuard = noop,
|
|
|
onCatch = noop,
|
|
|
onChange = noop,
|
|
@@ -25,34 +27,61 @@ function GuardState<T>(props: Props<T>) {
|
|
|
} = props;
|
|
|
|
|
|
const lockRef = useRef(false);
|
|
|
+ const saveRef = useRef(value);
|
|
|
+ const lastRef = useRef(0);
|
|
|
+ const timeRef = useRef<any>();
|
|
|
|
|
|
- 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;
|