Files
OpenFlare/frontend/hooks/use-controlled-state.tsx
T
ryan c76c5a697b 前端显式 any 类型清理
全前端显式 any 计数 2→0:Slot children?: any → ReactNode | MotionValue 联合(motion 真实类型),顺带修复潜在崩溃(原代码在 isValidElement 前访问 children.type,children 缺失时 TypeError,现无效 children 返回 null,hooks 无条件合规);useControlledState Rest extends any[] → unknown[]。两处 eslint-disable no-explicit-any 注释随之删除。

Experiments: #28
Metric: 全前端 any 2 → 0,tsc/eslint/vitest 全绿
2026-08-16 21:23:38 +08:00

42 lines
1005 B
TypeScript

import * as React from 'react';
interface CommonControlledStateProps<T> {
value?: T;
defaultValue?: T;
}
/**
* 受控状态 Hook
* 用于处理受控和非受控组件的状态管理
*
* @example
* ```tsx
* const [value, setValue] = useControlledState({ value: propValue, onChange: console.log })
* ```
*/
export function useControlledState<T, Rest extends unknown[] = []>(
props: CommonControlledStateProps<T> & {
onChange?: (value: T, ...args: Rest) => void;
},
): readonly [T, (next: T, ...args: Rest) => void] {
const { value, defaultValue, onChange } = props;
const [state, setInternalState] = React.useState<T>(
value !== undefined ? value : (defaultValue as T),
);
React.useEffect(() => {
if (value !== undefined) setInternalState(value);
}, [value]);
const setState = React.useCallback(
(next: T, ...args: Rest) => {
setInternalState(next);
onChange?.(next, ...args);
},
[onChange],
);
return [state, setState] as const;
}