The original FileProvider was a massive "god component" that violated the Single Responsibility Principle by handling:
- File operations and file tree management
- Editor state and content management
- Navigation history and file selection
- UI settings (spell check, suggestions, highlighting)
- Auto-saving logic
- File renaming logic
- 15+ individual useState hooks
- Complex interdependencies between states
- Side effects scattered throughout with numerous useEffects
We've broken down the monolithic FileProvider into 4 focused providers:
Responsibility: File operations and file tree management
State:
vaultFilesTree: File tree structurevaultFilesFlattened: Flattened file listexpandedDirectories: Directory expansion state
Operations:
createFileIfNotExists(): Create filesrenameFile(): Rename filesdeleteFile(): Delete filesreadFileContent(): Read file contentwriteFileAndCacheContent(): Write file contentprefetchFile(): Preload file contenthandleNewFileRenaming(): Auto-rename logichandleDirectoryToggle(): Directory expansionrefreshFileTree(): Refresh file tree
Responsibility: Editor state and content management
State:
currentlyOpenFilePath: Currently open filecurrentlyChangingFilePath: File switching stateneedToWriteEditorContentToDisk: Auto-save flagneedToIndexEditorContent: Indexing flag
Operations:
loadFileIntoEditor(): Load file into editorsaveCurrentlyOpenedFile(): Save current fileopenOrCreateFile(): Open or create filewriteEditorContentToDisk(): Write content to disktriggerIndexing(): Trigger file indexing
Auto-save Logic:
- Debounced auto-save on content changes
- Auto-save on window close
- Welcome note for first-time users
Responsibility: Navigation history and file selection
State:
navigationHistory: File navigation historyselectedDirectory: Currently selected directorynoteToBeRenamed: File rename statefileDirToBeRenamed: Directory rename state
Operations:
addToNavigationHistory(): Add to historyremoveFromNavigationHistory(): Remove from history- Directory and file selection management
Responsibility: UI-specific state management
State:
spellCheckEnabled: Spell check settingsuggestionsState: Editor suggestionshighlightData: Text highlighting data
Operations:
- Load spell check setting from storage
- Manage editor suggestions and highlighting
QueryClientProvider
└── FileCacheProvider
└── FileSystemProvider
└── EditorProvider
└── NavigationProvider
└── UISettingsProvider
└── FileProvider (Facade)
└── ChatProvider
└── ContentProvider
└── ModalProvider
Each provider has a clear, focused responsibility
- Smaller, manageable components
- Clear separation of concerns
- Easier to test and debug
- Logical grouping of related state
- Reduced interdependencies
- Cleaner state flow
- Easier to modify individual features
- Better code organization
- Clearer dependencies
- Providers can be used independently
- Easier to compose functionality
- Better for testing
The FileProvider now acts as a facade that combines all the functionality from the focused providers, ensuring backward compatibility with existing components.
Components can still use:
const {
vaultFilesTree,
currentlyOpenFilePath,
openOrCreateFile,
// ... all existing properties
} = useFileContext()Or use specific providers directly:
const { vaultFilesTree, createFileIfNotExists } = useFileSystem()
const { editor, loadFileIntoEditor } = useEditor()
const { navigationHistory, addToNavigationHistory } = useNavigation()
const { spellCheckEnabled, setSpellCheckEnabled } = useUISettings()- Gradual Migration: Components can gradually migrate to use specific providers
- Testing: Each provider can be tested independently
- Documentation: Add JSDoc comments to all provider methods
- Performance: Monitor for any performance impacts and optimize if needed
This refactoring transforms a monolithic, hard-to-maintain provider into a clean, modular architecture that follows React best practices and the Single Responsibility Principle.