-
Notifications
You must be signed in to change notification settings - Fork 54
Open
Description
Problem Description
Clients are generating code that calls merge() without save(), expecting the changes to be automatically persisted to the database. However, merge() is designed as a setState replacement for local updates (e.g., every keystroke) and does not automatically save to the database.
Example Code
import React from "react"
import { useFireproof } from "use-fireproof"
export default function PageToggle() {
const { database, useDocument } = useFireproof("page-toggle-db")
const { doc, merge } = useDocument({ isWhite: false, type: "page-state" })
const togglePage = () => {
merge({ isWhite: !doc.isWhite }) // ❌ Changes local state but doesn't persist
}
return (
<div>
<button onClick={togglePage}>Toggle Page</button>
<div style={{ backgroundColor: doc.isWhite ? 'white' : 'black' }}>
Current state: {doc.isWhite ? 'White' : 'Black'}
</div>
</div>
)
}Current Behavior vs Expected Behavior
Current Behavior:
merge()updates local component state only- Changes are lost on page refresh/component unmount
- Requires explicit
save()call for persistence
Expected Behavior (by clients):
merge()changes should be automatically persisted- State should survive page refreshes
- No manual
save()required for simple state updates
Impact
This creates a poor developer experience where:
- Clients write code that appears to work (UI updates)
- Data is lost unexpectedly on refresh
- Confusion about when persistence actually happens
- Need to remember to call
save()for everymerge()
Potential Solutions
Option 1: Auto-save with Debouncing
Add automatic persistence to merge() with configurable debouncing:
const { doc, merge } = useDocument({
isWhite: false
}, {
autoSave: true, // Enable auto-save on merge
autoSaveDelay: 300 // Debounce delay in ms
});Option 2: Auto-save on Unload
Automatically save pending changes when component unmounts or page unloads:
// Save any pending changes on cleanup
useEffect(() => {
return () => {
if (hasUnsavedChanges) {
save();
}
};
}, []);Recommended Approach
Option 1 + 2 (Auto-save with Debouncing) seems most practical:
- Maintains backward compatibility
- Provides expected behavior for simple use cases
- Allows opt-out for performance-sensitive scenarios
- Handles both frequent updates and state changes appropriately
Implementation Considerations
- Performance: Auto-save should be debounced to avoid excessive database writes
- Error Handling: Failed auto-saves should not break the UI
- Opt-out: Developers should be able to disable auto-save for performance-critical components
- Migration: Existing code should continue to work unchanged
- Documentation: Clear guidance on when to use auto-save vs manual save
Related Files
use-fireproof/react/use-document.ts(line 65-68: merge implementation)notes/use-document.md(documentation of current behavior)
This issue affects developer experience and could prevent adoption due to unexpected data loss.
Metadata
Metadata
Assignees
Labels
No labels