new
This commit is contained in:
83
src/components/AsyncSwitch/index.tsx
Normal file
83
src/components/AsyncSwitch/index.tsx
Normal file
@@ -0,0 +1,83 @@
|
||||
import { Switch, type SwitchProps } from 'antd';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
interface AsyncSwitchProps extends Omit<SwitchProps, 'onChange'> {
|
||||
// Execute the function asynchronously. If successful, the state will be switched. If failed, the state will remain unchanged.
|
||||
onAsyncChange: (checked: boolean) => Promise<any>;
|
||||
// Standard onChange, automatically injected in Form mode
|
||||
onChange?: (checked: boolean) => void;
|
||||
// Form.Item binds the value attribute to value by default, and the value attribute of Switch is checked. You can modify the bound value property through valuePropName.
|
||||
/**
|
||||
<Form.Item name="fieldA" valuePropName="checked">
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
*/
|
||||
value?: boolean;
|
||||
defaultChecked?: boolean;
|
||||
// Successfully/unsuccessfully hook
|
||||
onSuccess?: () => void;
|
||||
onError?: (err: any) => void;
|
||||
}
|
||||
|
||||
const AsyncSwitch: React.FC<AsyncSwitchProps> = (props) => {
|
||||
const {
|
||||
value,
|
||||
defaultChecked,
|
||||
onChange,
|
||||
onAsyncChange,
|
||||
onSuccess,
|
||||
onError,
|
||||
disabled,
|
||||
...rest
|
||||
} = props;
|
||||
// 1. Internal maintenance status, the initial value is checked first, followed by defaultChecked
|
||||
const [innerChecked, setInnerChecked] = useState<boolean>(
|
||||
!!(value ?? defaultChecked),
|
||||
);
|
||||
const [loading, setLoading] = useState<boolean>(false);
|
||||
|
||||
// 2. When the external checked changes (such as Form reset or external manual modification), synchronize the internal state
|
||||
useEffect(() => {
|
||||
if (value !== void 0) {
|
||||
setInnerChecked(value);
|
||||
}
|
||||
}, [value]);
|
||||
|
||||
const handleChange = async (val: boolean) => {
|
||||
setLoading(true);
|
||||
try {
|
||||
// Execute asynchronous logic
|
||||
await onAsyncChange(val);
|
||||
|
||||
// Processing after success:
|
||||
// If checked is not passed externally (uncontrolled mode), the internal state is updated
|
||||
if (value === void 0) {
|
||||
setInnerChecked(val);
|
||||
}
|
||||
|
||||
// Trigger external onChange (if it is Form, Form takes over the status update)
|
||||
onChange?.(val);
|
||||
|
||||
onSuccess?.();
|
||||
} catch (error) {
|
||||
console.warn('AsyncSwitch Error:', error);
|
||||
onError?.(error);
|
||||
// Failure does nothing and leaves the Switch as is
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Switch
|
||||
{...rest}
|
||||
loading={loading}
|
||||
// Always use innerChecked in preference as it is the final representation after synchronizing with the outside
|
||||
checked={innerChecked}
|
||||
onChange={handleChange}
|
||||
disabled={disabled || loading}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default AsyncSwitch;
|
||||
Reference in New Issue
Block a user