useControlledValue

useControlledValue(controlled, defaultValue, onChange)는 변경 콜백이 들어간 useControlledState입니다. [value, change]를 반환합니다. change(next, ...args)는 next가 마지막 렌더링의 값과 같으면(Object.is) 아무것도 하지 않으므로, 한 이벤트 안에서 같은 새 값으로 두 번 호출하면 onChange도 두 번 호출됩니다. 그렇지 않으면 비제어일 때 next를 저장한 다음, 제어 여부와 관계없이 onChange(next, ...args)를 호출합니다.

function Filter({ value, defaultValue = 'all', onValueChange }: FilterProps) {
	const [current, change] = useControlledValue(value, defaultValue, onValueChange)
	return (
		<select value={current} onChange={(event) => change(event.currentTarget.value)}>
			<option value="all">All</option>
			<option value="open">Open</option>
		</select>
	)
}

이유(reason) 같은 추가 인자는 onChange로 그대로 전달됩니다. useControlledValue<boolean, [reason: string]>(…)처럼 두 번째 타입 매개변수로 타입을 지정하세요. useControlledState와 마찬가지로 undefined는 비제어를 뜻하고, change는 업데이터 함수가 아닌 값을 받습니다.

언제 쓰나요

언제: 값 prop, 기본값, 그리고 값이 바뀔 때만 호출되어야 하는 변경 콜백을 받는 자체 컴포넌트.

쓰지 않을 때: 변경 콜백을 직접 호출하거나 콜백 없는 setter가 필요할 때 → useControlledState.

Props

useControlledValue props
이름타입필수기본값설명
controlledT | undefined예—값 prop. undefined는 비제어를 뜻하므로, 제어 상태의 빈 값에는 null을 쓰세요.
defaultValueT예—비제어일 때의 시작 값. 첫 렌더링에서만 읽습니다.
onChange(next: T, ...args: A) => void아니요—제어 여부와 관계없이 새 값과 이유(reason) 같은 추가 인자로 호출됩니다.