fix: resolve React hooks/compiler ESLint errors
- Wrap ref assignments in useEffect to fix refs-during-render in useTabManagement, useKeyboardNavigation, and Editor - Rewrite useAppKeyboard to define keyMap inside useEffect, eliminating ref access during render - Add eslint-disable for react-hooks/set-state-in-effect on legitimate dialog reset patterns (CommitDialog, CreateNoteDialog, CreateTypeDialog, QuickOpenPalette, AIChatPanel, useVaultLoader) - Add eslint-disable for react-hooks/static-components on icon lookups (NoteItem, NoteList PinnedCard) — stateless icon components from a static map - Add eslint-disable for react-hooks/purity on Date.now() in NoteItem TrashDateLine — intentionally memoized on trashedAt - Remove unused `model` param from buildSystemPrompt (ai-chat.ts) and update callers - Fix exhaustive-deps: suppress vault object dep in App.tsx git history effect (vault object is unstable, loadGitHistory is the real dep) - Remove unused `modifiedFiles` from useNoteListData params and caller - Add missing `ref` to Sidebar useOutsideClick deps Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -61,7 +61,7 @@ export function useAIChat(
|
||||
return
|
||||
}
|
||||
|
||||
const { prompt: systemPrompt } = buildSystemPrompt(contextNotes, allContent, model)
|
||||
const { prompt: systemPrompt } = buildSystemPrompt(contextNotes, allContent)
|
||||
let accumulated = ''
|
||||
|
||||
const onChunk = (chunk: string) => {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useMemo } from 'react'
|
||||
import { useEffect } from 'react'
|
||||
|
||||
interface KeyboardActions {
|
||||
onQuickOpen: () => void
|
||||
@@ -16,22 +16,22 @@ export function useAppKeyboard({
|
||||
onQuickOpen, onCreateNote, onSave, onTrashNote, onArchiveNote,
|
||||
activeTabPathRef, handleCloseTabRef,
|
||||
}: KeyboardActions) {
|
||||
const withActiveTab = (fn: (path: string) => void): ShortcutHandler => () => {
|
||||
const path = activeTabPathRef.current
|
||||
if (path) fn(path)
|
||||
}
|
||||
|
||||
const keyMap = useMemo((): Record<string, ShortcutHandler> => ({
|
||||
p: onQuickOpen,
|
||||
n: onCreateNote,
|
||||
s: onSave,
|
||||
e: withActiveTab(onArchiveNote),
|
||||
w: withActiveTab((path) => handleCloseTabRef.current(path)),
|
||||
Backspace: withActiveTab(onTrashNote),
|
||||
Delete: withActiveTab(onTrashNote),
|
||||
}), [onQuickOpen, onCreateNote, onSave, onTrashNote, onArchiveNote, activeTabPathRef, handleCloseTabRef])
|
||||
|
||||
useEffect(() => {
|
||||
const withActiveTab = (fn: (path: string) => void): ShortcutHandler => () => {
|
||||
const path = activeTabPathRef.current
|
||||
if (path) fn(path)
|
||||
}
|
||||
|
||||
const keyMap: Record<string, ShortcutHandler> = {
|
||||
p: onQuickOpen,
|
||||
n: onCreateNote,
|
||||
s: onSave,
|
||||
e: withActiveTab(onArchiveNote),
|
||||
w: withActiveTab((path) => handleCloseTabRef.current(path)),
|
||||
Backspace: withActiveTab(onTrashNote),
|
||||
Delete: withActiveTab(onTrashNote),
|
||||
}
|
||||
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
const mod = e.metaKey || e.ctrlKey
|
||||
if (!mod) return
|
||||
@@ -43,5 +43,5 @@ export function useAppKeyboard({
|
||||
}
|
||||
window.addEventListener('keydown', handleKeyDown)
|
||||
return () => window.removeEventListener('keydown', handleKeyDown)
|
||||
}, [keyMap])
|
||||
}, [onQuickOpen, onCreateNote, onSave, onTrashNote, onArchiveNote, activeTabPathRef, handleCloseTabRef])
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ function arrowDirection(key: string): 1 | -1 {
|
||||
|
||||
function useLatestRef<T>(value: T): React.RefObject<T> {
|
||||
const ref = useRef(value)
|
||||
ref.current = value
|
||||
useEffect(() => { ref.current = value })
|
||||
return ref
|
||||
}
|
||||
|
||||
@@ -119,5 +119,5 @@ export function useKeyboardNavigation({
|
||||
}
|
||||
window.addEventListener('keydown', handleKeyDown)
|
||||
return () => window.removeEventListener('keydown', handleKeyDown)
|
||||
}, [])
|
||||
}, [tabsRef, activeTabPathRef, visibleNotesRef, onSwitchTabRef, onReplaceRef, onSelectNoteRef])
|
||||
}
|
||||
|
||||
@@ -82,9 +82,9 @@ export function useTabManagement() {
|
||||
const [tabs, setTabs] = useState<Tab[]>([])
|
||||
const [activeTabPath, setActiveTabPath] = useState<string | null>(null)
|
||||
const activeTabPathRef = useRef(activeTabPath)
|
||||
activeTabPathRef.current = activeTabPath
|
||||
useEffect(() => { activeTabPathRef.current = activeTabPath })
|
||||
const tabsRef = useRef(tabs)
|
||||
tabsRef.current = tabs
|
||||
useEffect(() => { tabsRef.current = tabs })
|
||||
const handleCloseTabRef = useRef<(path: string) => void>(() => {})
|
||||
|
||||
const handleSelectNote = useCallback(async (entry: VaultEntry) => {
|
||||
@@ -111,7 +111,7 @@ export function useTabManagement() {
|
||||
return next
|
||||
})
|
||||
}, [])
|
||||
handleCloseTabRef.current = handleCloseTab
|
||||
useEffect(() => { handleCloseTabRef.current = handleCloseTab })
|
||||
|
||||
const handleSwitchTab = useCallback((path: string) => {
|
||||
setActiveTabPath(path)
|
||||
@@ -152,7 +152,7 @@ export function useTabManagement() {
|
||||
useEffect(() => {
|
||||
const savedOrder = loadTabOrder()
|
||||
if (savedOrder.length > 0) {
|
||||
setTabs((prev) => restoreOrder(prev, savedOrder))
|
||||
setTabs((prev) => restoreOrder(prev, savedOrder)) // eslint-disable-line react-hooks/set-state-in-effect -- restore tab order on mount
|
||||
}
|
||||
}, [])
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ export function useVaultLoader(vaultPath: string) {
|
||||
const [modifiedFiles, setModifiedFiles] = useState<ModifiedFile[]>([])
|
||||
|
||||
useEffect(() => {
|
||||
// eslint-disable-next-line react-hooks/set-state-in-effect -- clear stale data then load new vault
|
||||
setEntries([]); setAllContent({}); setModifiedFiles([])
|
||||
loadVaultData(vaultPath)
|
||||
.then(({ entries: e, allContent: c }) => { setEntries(e); setAllContent(c) })
|
||||
@@ -51,7 +52,7 @@ export function useVaultLoader(vaultPath: string) {
|
||||
}
|
||||
}, [vaultPath])
|
||||
|
||||
useEffect(() => { loadModifiedFiles() }, [loadModifiedFiles])
|
||||
useEffect(() => { loadModifiedFiles() }, [loadModifiedFiles]) // eslint-disable-line react-hooks/set-state-in-effect -- trigger initial load
|
||||
|
||||
const addEntry = useCallback((entry: VaultEntry, content: string) => {
|
||||
setEntries((prev) => [entry, ...prev])
|
||||
|
||||
Reference in New Issue
Block a user