fix(component): fix stale closure in MaterialTypeManagementDialog
Fix issue where keyword field was not editable after adding new row via Insert key or Add button. Root cause was incomplete useCallback dependencies in handleKeyDown, causing it to capture stale references to insertNewRow, deleteRow, saveEdit, and cancelEdit functions. Changes: - Wrap insertNewRow with useCallback (deps: isAdmin, currentUsername) - Wrap deleteRow with useCallback (deps: none) - Wrap startEdit with useCallback (deps: rows) - Wrap saveEdit with useCallback (deps: editingCell, editValue) - Wrap cancelEdit with useCallback (deps: none) - Update handleKeyDown dependency array to include all referenced functions This ensures all callbacks have access to the latest props and state, preventing the edit mode initialization failure. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -115,31 +115,8 @@ export const MaterialTypeManagementDialog: React.FC<MaterialTypeManagementDialog
|
|||||||
return rows.filter((row) => selectedManagers.has(row.record.managerName) || row.state === 'new')
|
return rows.filter((row) => selectedManagers.has(row.record.managerName) || row.state === 'new')
|
||||||
}, [rows, isAdmin, selectedManagers])
|
}, [rows, isAdmin, selectedManagers])
|
||||||
|
|
||||||
// Handle keyboard events
|
|
||||||
const handleKeyDown = useCallback(
|
|
||||||
(event: React.KeyboardEvent) => {
|
|
||||||
if (editingCell) {
|
|
||||||
if (event.key === 'Enter') {
|
|
||||||
saveEdit()
|
|
||||||
} else if (event.key === 'Escape') {
|
|
||||||
cancelEdit()
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event.key === 'Insert') {
|
|
||||||
event.preventDefault()
|
|
||||||
insertNewRow()
|
|
||||||
} else if (event.key === 'Delete' && selectedRowIndex !== null) {
|
|
||||||
event.preventDefault()
|
|
||||||
deleteRow(selectedRowIndex)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[editingCell, selectedRowIndex]
|
|
||||||
)
|
|
||||||
|
|
||||||
// Insert new row
|
// Insert new row
|
||||||
const insertNewRow = () => {
|
const insertNewRow = useCallback(() => {
|
||||||
const newRow: RowState = {
|
const newRow: RowState = {
|
||||||
record: {
|
record: {
|
||||||
materialName: '',
|
materialName: '',
|
||||||
@@ -157,10 +134,10 @@ export const MaterialTypeManagementDialog: React.FC<MaterialTypeManagementDialog
|
|||||||
}, 0)
|
}, 0)
|
||||||
return [...prev, newRow]
|
return [...prev, newRow]
|
||||||
})
|
})
|
||||||
}
|
}, [isAdmin, currentUsername])
|
||||||
|
|
||||||
// Delete row
|
// Delete row
|
||||||
const deleteRow = (index: number) => {
|
const deleteRow = useCallback((index: number) => {
|
||||||
setRows((prev) => {
|
setRows((prev) => {
|
||||||
const newRows = [...prev]
|
const newRows = [...prev]
|
||||||
const row = newRows[index]
|
const row = newRows[index]
|
||||||
@@ -174,19 +151,19 @@ export const MaterialTypeManagementDialog: React.FC<MaterialTypeManagementDialog
|
|||||||
return newRows
|
return newRows
|
||||||
})
|
})
|
||||||
setSelectedRowIndex(null)
|
setSelectedRowIndex(null)
|
||||||
}
|
}, [])
|
||||||
|
|
||||||
// Start editing a cell
|
// Start editing a cell
|
||||||
const startEdit = (rowIndex: number, field: string) => {
|
const startEdit = useCallback((rowIndex: number, field: string) => {
|
||||||
const row = rows[rowIndex]
|
const row = rows[rowIndex]
|
||||||
if (row.state === 'deleted') return
|
if (row.state === 'deleted') return
|
||||||
|
|
||||||
setEditingCell({ rowIndex, field })
|
setEditingCell({ rowIndex, field })
|
||||||
setEditValue(row.record[field as keyof MaterialTypeRecord] as string)
|
setEditValue(row.record[field as keyof MaterialTypeRecord] as string)
|
||||||
}
|
}, [rows])
|
||||||
|
|
||||||
// Save edit
|
// Save edit
|
||||||
const saveEdit = () => {
|
const saveEdit = useCallback(() => {
|
||||||
if (!editingCell) return
|
if (!editingCell) return
|
||||||
|
|
||||||
const { rowIndex, field } = editingCell
|
const { rowIndex, field } = editingCell
|
||||||
@@ -209,13 +186,36 @@ export const MaterialTypeManagementDialog: React.FC<MaterialTypeManagementDialog
|
|||||||
|
|
||||||
setEditingCell(null)
|
setEditingCell(null)
|
||||||
setEditValue('')
|
setEditValue('')
|
||||||
}
|
}, [editingCell, editValue])
|
||||||
|
|
||||||
// Cancel edit
|
// Cancel edit
|
||||||
const cancelEdit = () => {
|
const cancelEdit = useCallback(() => {
|
||||||
setEditingCell(null)
|
setEditingCell(null)
|
||||||
setEditValue('')
|
setEditValue('')
|
||||||
}
|
}, [])
|
||||||
|
|
||||||
|
// Handle keyboard events
|
||||||
|
const handleKeyDown = useCallback(
|
||||||
|
(event: React.KeyboardEvent) => {
|
||||||
|
if (editingCell) {
|
||||||
|
if (event.key === 'Enter') {
|
||||||
|
saveEdit()
|
||||||
|
} else if (event.key === 'Escape') {
|
||||||
|
cancelEdit()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.key === 'Insert') {
|
||||||
|
event.preventDefault()
|
||||||
|
insertNewRow()
|
||||||
|
} else if (event.key === 'Delete' && selectedRowIndex !== null) {
|
||||||
|
event.preventDefault()
|
||||||
|
deleteRow(selectedRowIndex)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[editingCell, selectedRowIndex, insertNewRow, deleteRow, saveEdit, cancelEdit]
|
||||||
|
)
|
||||||
|
|
||||||
// Save all changes
|
// Save all changes
|
||||||
const handleSave = async () => {
|
const handleSave = async () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user