하나의 값, 하나의 주인
Single Owner And Controlled Inputs
Keep one authoritative value when several controls edit the same setting.
이 자료로 구현하기
원문 주소와 버전이 포함된 요청문입니다. 복사한 뒤 만들 화면과 요구사항을 채워 에이전트에게 전달하세요.
FROM PRINCIPLE TO PRACTICE
이 원리로 만든 예제 23
예제를 열어 직접 조작하고, 관찰한 동작을 이 문서의 원리와 비교해 보세요.
dithering
- 컨트롤·코드·프리셋이 읽는 하나의 매개변수
원본 문서 화면은 useControls의 params를 Dithering, ShaderContainer, ShaderDetails에 전달합니다. 프리셋 선택과 개별 조절 뒤에도 코드에 표시된 shape·type·size와 실제 셰이더 입력이 일치하는지 확인할 수 있는 구조입니다.
- 컨트롤·코드·프리셋이 읽는 하나의 매개변수
static mesh gradient
- 색 배열과 숫자 입력을 함께 바꾸는 프리셋
원본 컨트롤은 colors를 useColors로, 숫자 입력을 useControls로 관리합니다. 프리셋은 두 소유 값을 각각 갱신하고 ShaderContainer·ShaderDetails에는 다시 합친 객체를 전달합니다. 프리셋 이름만 바뀌고 이전 색이나 wave 값이 남는 실패를 확인할 지점입니다.
- 색 배열과 숫자 입력을 함께 바꾸는 프리셋
Card Accordion · Myna UI
- 세 질문을 묶는 하나의 열림 상태
Accordion2는 type="single"과 collapsible을 같은 루트에 지정합니다. item-1·2·3이 그 상태를 공유하며 초기 열린 값은 지정하지 않습니다. 바깥 카드가 하나인 것과 단일 선택 상태는 별개의 결정입니다.
- 세 질문을 묶는 하나의 열림 상태
연결된 예제 20개 더 보기
Separate Card Accordion · Myna UI
- 떨어진 카드도 열림 상태는 공유
세 질문은 각각 테두리가 있는 AccordionItem이지만 루트는 하나입니다. type="single"과 collapsible로 한 질문 또는 아무 질문도 열리지 않은 상태를 표현합니다.
- 떨어진 카드도 열림 상태는 공유
Form Section Accordion · Myna UI
- 입력값의 수명과 섹션의 열림
세 섹션의 Input에는 value·onChange가 없고 바깥 form이나 저장 상태도 없습니다. 단일 아코디언을 닫을 때 입력값을 유지할 별도 초안 소유자나 forceMount는 선언하지 않습니다. 접었다 다시 열었을 때의 값 보존을 가정하면 안 됩니다.
- 입력값의 수명과 섹션의 열림
Centered Alert Dialog · Myna UI
- 표현은 중앙 정렬, 상태는 확인 창 루트
AlertDialog3도 하나의 비제어 AlertDialog 루트를 사용합니다. 중앙 정렬 헤더와 text-balance는 문구 표현만 바꾸며 Cancel·Continue 이외의 업무 상태나 삭제 요청을 만들지 않습니다.
- 표현은 중앙 정렬, 상태는 확인 창 루트
Closable Banner · Origin UI
- 프리미티브의 닫기 요청과 부모 상태
BannerClosable은 isClosable과 onClose를 Banner에 전달합니다. 프리미티브는 닫기 버튼을 렌더링하고 받은 콜백을 onClick에 연결할 뿐, 자체 표시 상태는 갖지 않습니다. 실제 제거는 부모의 setIsVisible(false)와 null 반환이 담당합니다.
- 프리미티브의 닫기 요청과 부모 상태
Profile Dropdown · Myna UI
- 고정 Invisible 값의 상태 계약
Current Status의 RadioGroup은 value="invisible"만 받고 onValueChange가 없습니다. Online을 선택해도 원본이 새 상태를 저장할 경로는 없고 Offline은 disabled입니다. Visibility 하위 메뉴의 Online과도 값을 공유하지 않습니다.
- 고정 Invisible 값의 상태 계약
Calendar Form · Ved UI
- 선택 날짜와 표시 문자열의 소유자
CalendarForm의 dob 필드를 Calendar.selected와 버튼의 format(field.value, "PPP")가 함께 읽습니다. 선택 이벤트는 field.onChange로 전달됩니다. 미선택 상태에는 안내 문구를 표시하며, 이 예제에는 날짜의 서버 직렬화나 locale 설정이 없습니다.
- 선택 날짜와 표시 문자열의 소유자
Dual Range Form · Ved UI
- 슬라이더 표시와 폼 값의 이중 보관
DualRangeSliderForm은 [25, 75]를 sliderValue 상태와 폼 range의 초기값에 넣습니다. 핸들을 움직일 때 handleSliderChange가 둘 다 갱신하지만 화면의 Slider와 output은 sliderValue를 읽습니다. 폼만 reset하거나 setValue하는 외부 경로를 sliderValue로 되돌리는 코드는 없습니다.
- 슬라이더 표시와 폼 값의 이중 보관
Select Form · Ved UI
- 초기값 전달과 제어 값 전달의 차이
SelectForm은 onValueChange를 field.onChange로 연결하지만 Select에는 value 대신 defaultValue={field.value}를 넘깁니다. 사용자의 선택을 폼으로 보내는 경로는 있으나 이후 폼 값의 외부 변경을 제어 prop으로 전달하지는 않습니다. 이 데모에는 재설정 버튼이 없습니다.
- 초기값 전달과 제어 값 전달의 차이
Basic Pagination · Myna UI
- 현재 페이지는 2로 고정
원본은 1·2·3·8·9·10을 직접 나열하고 2에만 isActive를 붙입니다. 모든 href가 #이고 페이지 상태·조회 콜백이 없습니다. Previous나 Next를 눌러도 현재 페이지를 계산할 코드가 없습니다.
- 현재 페이지는 2로 고정
Table Column Visibility · 21st/shadcn
- 머리글과 행이 같은 열 선택을 사용
selectedColumns가 초기 6개 열을 보유하고 CheckboxItem checked와 헤더·본문의 map이 모두 이를 참조합니다. handleColumnToggle은 함수형 상태 갱신으로 현재 배열에서 열을 제거하거나 추가합니다. usersData 5행 자체는 변경하지 않습니다.
- 머리글과 행이 같은 열 선택을 사용
Account Tabs With Card · Myna UI
- 다섯 화면의 선택 상태
Tabs는 defaultValue="overview"에서 시작하고 overview·saved·groups·comments·backup 값이 Trigger와 Content를 연결합니다. 선택 상태를 바깥으로 제어하지 않고 Radix Tabs에 맡깁니다. URL·저장소와 동기화하는 코드도 없습니다.
- 다섯 화면의 선택 상태
Bookmark Toggle · Origin UI
- 북마크 상태 하나가 표현을 결정
Component의 bookmarked가 Toggle의 pressed와 TooltipContent 문구를 결정하고 onPressedChange가 같은 값을 갱신합니다. data-[state=on]은 선택 시 색을 바꾸며 aria-label은 항상 Bookmark this입니다. 상태는 로컬이고 서버·계정·저장소에 기록하지 않습니다.
- 북마크 상태 하나가 표현을 결정
Theme Icon Toggle · Origin UI
- 아이콘 상태와 호스트 테마의 별도 소유자
데모의 theme은 light로 시작하는 로컬 문자열이고 Toggle의 pressed 및 다음 행동을 설명하는 aria-label을 결정합니다. onPressedChange는 이 문자열만 바꾸며 document·저장소·호스트 테마를 갱신하지 않습니다. 호스트의 밝음·어두움 선택은 별도의 URL theme 값으로 적용됩니다.
- 아이콘 상태와 호스트 테마의 별도 소유자
쿠키 선택 안내 · Origin UI
- 쿠키 선택을 소유하는 상태가 없다
comp-293은 We Value Your Privacy 🍪와 쿠키 설명 아래에 기본 스타일 Accept와 outline Decline을 둡니다. 선택 prop, 로컬 상태, 저장 코드, 클릭 처리기가 없습니다. 두 버튼은 선택 가능한 모양을 보여 주지만 실제 선호를 수락하거나 기억하지 않습니다.
- 쿠키 선택을 소유하는 상태가 없다
Checkbox Group · Fluid Functionalism
- 첫째·셋째 선택을 소유하는 값 하나
어댑터는 한국어 항목 5개와 초기 인덱스 [0,2]를 사용합니다. 하나의 checked Set을 그룹의 checkedIndices와 각 행의 checked에 전달합니다. 토글은 이전 Set을 복사한 뒤 해당 인덱스를 추가·삭제하며, 작성자 컴포넌트는 자체 선택 저장소를 만들지 않습니다. 문구는 새로 작성한 것이며 원래 CDN 데모 코드를 재배포한 구성이 아닙니다.
- 첫째·셋째 선택을 소유하는 값 하나
Fully Checked Group · Fluid Functionalism
- 네 항목의 초기 선택과 이후 개별 변경
이 변형은 다른 두 예제와 달리 항목이 4개이고 [0,1,2,3]으로 시작합니다. 이후에는 각 행이 같은 Set의 자기 인덱스만 켜고 끕니다. 전부 선택이라는 이름이 매번 네 항목을 강제로 유지하거나 전체 선택 버튼을 제공한다는 뜻은 아닙니다. 처음부터 체크된 표시는 skipAnimation으로 경로 그리기의 시작값을 1로 지정합니다.
- 네 항목의 초기 선택과 이후 개별 변경
Depth field · Light and distance
- Depth field · Light and distance · renderField
A deterministic point projection links size and trace length to depth. A stationary frame is useful before playback, and the same phase can be revisited with a native range control. This binding describes the authored study; it is not verification of the original.
- Depth field · Light and distance · renderField
Fieldwork · A workspace that remembers
- Fieldwork · A workspace that remembers · renderNavigation
The shell stores selected view, group disclosure and sidebar visibility independently. Hiding navigation releases its space while the breadcrumb and content continue to read the same selection. This binding describes the authored study; it is not verification of the original.
- Fieldwork · A workspace that remembers · renderNavigation
Rotating words달라지는 한 단어
- 한 번의 선택으로 결정하는 다음 단어
버튼을 누르면 세 단어를 순환하는 인덱스를 즉시 갱신합니다. 새 단어를 먼저 쓰고 등장 효과를 다시 시작하므로 움직임이 정지되어도 선택 자체는 진행됩니다.
- 한 번의 선택으로 결정하는 다음 단어
Glowing pricing선택하고 싶은 요금제
- 선택 주기와 금액을 함께 갱신하기
월간·연간 버튼 중 하나를 누르면 눌림 상태와 표시 금액을 함께 바꿉니다. 금액은 버튼의 고정 값 24와 18이며 단위 문구는 계속 월 기준입니다. 실제 결제 주기나 할인 계산을 검증하는 계약은 없습니다.
- 선택 주기와 금액을 함께 갱신하기
Repository Boundary
Keep one authoritative value when several controls edit the same setting. This pattern belongs to Design Engineering and adds no Layout CSS or shared store implementation.
Reusable Method
Use when sibling or nested controls must agree immediately. Keep a private disclosure local when no other surface needs its value. Choose the nearest owner that survives every participating control.
State Model And Ownership
The owner stores value; controls receive it and emit an intent. Temporary text composition may stay local, but must have an explicit commit/reset boundary. Owner validation can reject an intent without creating a second accepted value.
Transitions
| Event and precondition | Next state | Effect or invariant |
|---|---|---|
| Control proposes an allowed value | Owner replaces value | All readers observe the same accepted value |
| Control proposes an invalid value | Unchanged | Return rejection; do not pretend the value committed |
| Owner resets externally | New owner value | Every controlled reader reflects reset |
Minimal Executable Example
Run this standalone JavaScript block with Node.js 22 or newer, or run all pattern examples from a repository checkout with bun run test:state-management. The assertions exercise the local model, not a browser or backend.
import assert from "node:assert/strict";
let value = "compact";
function propose(next) {
if (!["compact", "comfortable"].includes(next)) return false;
value = next;
return true;
}
const toolbar = { read: () => value, change: propose };
const settings = { read: () => value, change: propose };
assert.equal(toolbar.change("comfortable"), true);
assert.equal(settings.read(), "comfortable");
assert.equal(settings.change("invalid"), false);
assert.equal(toolbar.read(), "comfortable");
value = "compact";
assert.equal(settings.read(), "compact");What Breaks If Removed
If each control copies the initial value into its own accepted state, changing the toolbar leaves settings stale. Synchronizing both copies with reciprocal callbacks introduces a second ordering problem.
Composition And Substitution
Compose with derived state for summaries and identity reset for account changes. A framework context or store can transport this owner; it does not decide who owns the value.
Opinionated Guidance
Name the write API as an intent when the owner may reject or normalize it. Distinguish a local editing buffer from the accepted value in component inputs.
Platform-Specific Guidance
Native controls still need accessible names and correct value semantics. Preserve IME composition when adapting text inputs; do not normalize every keystroke without an input contract.
Unsupported Absolutes
A shared owner does not require an application-wide store or prove efficient subscriptions.
Verification Contract
- Edit from either control, then reset from the parent; both readers must agree.
- Reject an invalid intent and verify the UI exposes the rejection.
- Remove and recreate one reader; it must receive the current value.
Record actual outcomes separately using the verification matrix.
Source, License, And Attribution
Locally authored synthesis and examples. No upstream implementation is copied. These experimental contracts describe consumer-owned behavior; review when a failure, ownership change, or platform change invalidates an assumption.
IA Navigation
Parent: State Management. Next: Continue the state management route.


