저장하지 않은 변경 지키기
Unsaved Changes And Navigation
Make leaving an edited screen an explicit decision without losing the current draft.
GitHub에서 원문 보기 ↗새 탭Repository Boundary
Make leaving an edited screen an explicit decision without losing the current draft. This pattern belongs to Design Engineering and adds no Layout CSS or shared store implementation.
Reusable Method
Use when route changes can discard meaningful user work. Do not interrupt navigation for harmless transient selection or derived values.
State Model And Ownership
The form owns dirty; the router integration owns a pending destination and guard status. The confirmation owns a decision, not a second copy of form data. Save-and-leave must recheck dirty after acknowledgement.
Transitions
| Event and precondition | Next state | Effect or invariant |
|---|---|---|
| Navigate while clean | Destination committed | Leave normally |
| Navigate while dirty | Decision pending | Retain current screen and destination |
| Cancel decision | Pending cleared | Stay and return focus |
| Discard decision | Destination committed | Explicitly abandon draft |
| Save fails or later edits remain | Stay | Preserve draft and offer recovery |
Minimal Executable Example
Run this standalone JavaScript block with Node.js 22 or newer, or run all pattern examples from a repository checkout with npm run test:state-management. The assertions exercise the local model, not a browser or backend.
import assert from "node:assert/strict";
let dirty = true, pending = null, location = "editor";
function navigate(to) {
if (dirty) pending = to;
else location = to;
}
function decide(choice) {
if (choice === "cancel") pending = null;
if (choice === "discard" && pending !== null) {
dirty = false;
location = pending;
pending = null;
}
}
navigate("list");
decide("cancel");
assert.equal(location, "editor");
assert.equal(dirty, true);
navigate("list");
decide("discard");
assert.equal(location, "list");
assert.equal(pending, null);What Breaks If Removed
If route mutation happens before the guard, the form may already be destroyed when Cancel runs. If any save success releases navigation, later unsaved edits can still be lost.
Composition And Substitution
Use submitted snapshot for Save-and-leave and URL state for committed destinations. A pending destination is not a committed URL.
Opinionated Guidance
Declare what a second navigation attempt does while confirmation is open: this model replaces the destination with the latest attempt. Verify the displayed decision matches it.
Platform-Specific Guidance
In-app routing and document unload have different capabilities. Browser unload prompts are constrained and unreliable as a sole recovery strategy; use optional draft persistence when needed. Verify keyboard focus entry/return for the confirmation.
Platform reference: MDN API documentation, checked 2026-09-16. This supports the named browser boundary; the model and product policy remain local synthesis.
Unsupported Absolutes
An in-memory guard cannot guarantee preservation after process termination or device failure.
Verification Contract
- Cancel a guarded route change; values and focus return to the editor.
- Attempt another destination while the decision is open; apply the declared policy.
- Save A, edit B, then acknowledge A; do not leave with dirty B.
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.