편집한 값과 저장한 값
Draft And Persisted Baseline
Preserve editable work while distinguishing it from the last acknowledged saved value.
이 자료로 구현하기
원문 주소와 버전이 포함된 요청문입니다. 복사한 뒤 만들 화면과 요구사항을 채워 에이전트에게 전달하세요.
FROM PRINCIPLE TO PRACTICE
이 원리로 만든 예제 3
예제를 열어 직접 조작하고, 관찰한 동작을 이 문서의 원리와 비교해 보세요.
Human Review Panel · Extend UI
- 원래 추출 값과 수정할 검토 값
HumanReviewPanel은 fields.actual로 원래 값을 만들고 fields.expected로 편집 상태를 초기화합니다. 변경은 expected 객체만 갱신하고 Undo는 해당 field.expected로 되돌립니다. 첫 필드의 Jan 1-31, 2026과 January 1-31, 2026 차이도 원래 예시 데이터입니다. 이 패널은 서버 저장을 호출하지 않으며 props의 기준이 바뀌면 현재 편집 상태를 다시 초기화합니다.
- 원래 추출 값과 수정할 검토 값
변경 취소 안내 · Origin UI
- 되돌릴 변경과 기준값이 없는 Undo
comp-287은 You‘ve made changes! 문구와 작은 Undo Button을 표시합니다. 편집값, 이전 값, 서버 확인, 클릭 처리기는 없습니다. 따라서 원본의 Undo는 보이는 행동 이름이며 실제 변경을 되돌릴 상태 모델은 아닙니다.
- 되돌릴 변경과 기준값이 없는 Undo
저장 스냅샷·중복 제출·나가기Save ownership
- 저장 작업의 소유권과 응답 순서
현재 초안과 저장된 기준값을 비교하고 실패 시 초안을 보존합니다.
- 저장 작업의 소유권과 응답 순서
Repository Boundary
Preserve editable work while distinguishing it from the last acknowledged saved value. This pattern belongs to Design Engineering and adds no Layout CSS or shared store implementation.
Reusable Method
Use for explicit Save/Cancel forms. For immediate committed toggles, use an operation contract instead of inventing a long-lived draft.
State Model And Ownership
The form owns a draft, persistence supplies the baseline, and dirty is derived using domain equality. This example uses a single string. A remote update while dirty needs merge, conflict, or reload policy; never silently replace the draft.
Transitions
| Event and precondition | Next state | Effect or invariant |
|---|---|---|
| Edit | Draft changes | Baseline stays acknowledged |
| Discard | Draft becomes baseline | No persistence request |
| Remote update while dirty | Conflict retained | Keep draft until the user resolves it |
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 baseline = "Original";
let draft = baseline;
const dirty = () => draft !== baseline;
draft = "Edited";
assert.equal(dirty(), true);
const remote = "Remote edit";
const conflict = dirty() && remote !== baseline;
assert.equal(conflict, true);
assert.equal(draft, "Edited");
draft = baseline; // Explicit discard, not an automatic refresh.
assert.equal(dirty(), false);What Breaks If Removed
Binding fields directly to the cached saved object makes Cancel impossible and may tell other readers that unsaved edits are persisted. An independent dirty boolean can remain true after editing back to the baseline.
Composition And Substitution
Submitted snapshot owns save acknowledgement. Unsaved navigation uses dirty as an input. Do not let the router own a second draft.
Opinionated Guidance
Choose baseline equality and server normalization rules before wiring a generic deep comparison. For nested drafts, prevent shared mutable references to the baseline.
Platform-Specific Guidance
Use native form labels and validation relationships. Route-level forms may outlive individual fields; unmounting a field should not implicitly discard the form.
Unsupported Absolutes
A baseline is an acknowledged observation, not a guarantee that nobody else edited the server since then.
Verification Contract
- Edit then restore the original value; dirty must become false.
- Receive a remote update while dirty; preserve entered values.
- Discard explicitly; restore the acknowledged baseline without sending a save.
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.


