Skip to content

Commit

Permalink
refactor(ui/hooks): useControllableState 내부 type 명확화, value 관련 명칭 sta…
Browse files Browse the repository at this point in the history
…te로 수정 (#330)

* refactor(ui/hooks): useControllableState 내부 type 명확화, value 관련 명칭 state로 수정

* refactor(ui/components): useControllableState 변경사항 반영
  • Loading branch information
sukvvon authored Aug 22, 2024
1 parent f10b1ec commit 401a3ec
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 30 deletions.
6 changes: 3 additions & 3 deletions packages/ui/src/components/checkbox/checkbox.primitive.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,16 @@ const Checkbox = forwardRef<CheckboxProps, 'button'>(
value = 'on',
required,
disabled,
defaultChecked,
checked: checkedProp,
defaultChecked,
onCheckedChange,
...restProps
} = props;

const [button, setButton] = useState<HTMLButtonElement | null>(null);
const [checked = false, setChecked] = useControllableState({
value: checkedProp,
defaultValue: defaultChecked,
prop: checkedProp,
defaultProp: defaultChecked,
onChange: onCheckedChange,
});

Expand Down
46 changes: 19 additions & 27 deletions packages/ui/src/hooks/use-controllable-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,44 +7,36 @@ import {
import { useCallbackRef } from './use-callback-ref';

type UseControllableStateProps<T> = {
value?: T;
defaultValue?: T;
onChange?: (value: T) => void;
shouldUpdate?: (prev: T, next: T) => boolean;
prop?: T;
defaultProp?: T;
onChange?: (state: T) => void;
};

type SetStateFn<T> = (prevState?: T) => T;

export function useControllableState<T>(props: UseControllableStateProps<T>) {
const {
value: valueProp,
defaultValue,
onChange = () => {},
shouldUpdate = (prev, next) => prev !== next,
} = props;
const { prop, defaultProp, onChange = () => {} } = props;

const [uncontrolledProp, setUncontrolledProp] = useState<T | undefined>(
defaultProp,
);
const isControlled = prop !== undefined;
const state = isControlled ? prop : uncontrolledProp;
const handleChange = useCallbackRef(onChange);
const shouldUpdateProp = useCallbackRef(shouldUpdate);

const [uncontrolledValue, setUncontrolledValue] = useState(defaultValue as T);
const isControlled = valueProp !== undefined;
const value = isControlled ? valueProp : uncontrolledValue;

const setValue: Dispatch<SetStateAction<T>> = useCallback(
const setState: Dispatch<SetStateAction<T | undefined>> = useCallback(
(next) => {
const setter = next as (prevState?: T) => T;
const nextValue = typeof next === 'function' ? setter(value) : next;
const setter = next as SetStateFn<T>;
const nextState = typeof next === 'function' ? setter(state) : next;

if (!shouldUpdateProp(value, nextValue)) {
return;
}
if (state === nextState) return;

if (!isControlled) {
setUncontrolledValue(nextValue);
}
if (!isControlled) setUncontrolledProp(nextState);

handleChange(nextValue);
handleChange(nextState as T);
},
[handleChange, isControlled, shouldUpdateProp, value],
[handleChange, isControlled, state],
);

return [value, setValue] as const;
return [state, setState] as const;
}

0 comments on commit 401a3ec

Please sign in to comment.