diff --git a/src/components/datagrid/utils/focus.test.tsx b/src/components/datagrid/utils/focus.test.tsx index 5ea6b103bf8..f902645eeda 100644 --- a/src/components/datagrid/utils/focus.test.tsx +++ b/src/components/datagrid/utils/focus.test.tsx @@ -60,16 +60,22 @@ describe('useFocus', () => { }); describe('focusedCell / setFocusedCell', () => { + const { + return: { focusedCell, setFocusedCell }, + getUpdatedState, + } = testCustomHook(() => useFocus(mockArgs)); + it('gets and sets the focusedCell state', () => { - const { - return: { focusedCell, setFocusedCell }, - getUpdatedState, - } = testCustomHook(() => useFocus(mockArgs)); expect(focusedCell).toEqual(undefined); - act(() => setFocusedCell([2, 2])); expect(getUpdatedState().focusedCell).toEqual([2, 2]); }); + + it('does not update if setFocusedCell is called with the same cell X/Y coordinates', () => { + const focusedCellInMemory = getUpdatedState().focusedCell; + act(() => getUpdatedState().setFocusedCell([2, 2])); + expect(getUpdatedState().focusedCell).toBe(focusedCellInMemory); // Would fail if the exact same array wasn't returned + }); }); describe('focusFirstVisibleInteractiveCell', () => { diff --git a/src/components/datagrid/utils/focus.ts b/src/components/datagrid/utils/focus.ts index 40d992b857d..e19495ea2fb 100644 --- a/src/components/datagrid/utils/focus.ts +++ b/src/components/datagrid/utils/focus.ts @@ -67,10 +67,22 @@ export const useFocus = ({ EuiDataGridFocusedCell | undefined >(undefined); - const setFocusedCell = useCallback((focusedCell: EuiDataGridFocusedCell) => { - _setFocusedCell(focusedCell); - setIsFocusedCellInView(true); // scrolling.ts ensures focused cells are fully in view - }, []); + const setFocusedCell = useCallback( + (nextFocusedCell: EuiDataGridFocusedCell) => { + // If the x/y coordinates remained the same, don't update. This keeps the focusedCell + // reference stable, and allows it to be used in places that need reference equality. + if ( + nextFocusedCell[0] === focusedCell?.[0] && + nextFocusedCell[1] === focusedCell?.[1] + ) { + return; + } + + _setFocusedCell(nextFocusedCell); + setIsFocusedCellInView(true); // scrolling.ts ensures focused cells are fully in view + }, + [focusedCell] + ); const previousCell = useRef(undefined); useEffect(() => { diff --git a/upcoming_changelogs/6007.md b/upcoming_changelogs/6007.md new file mode 100644 index 00000000000..e64c827f88e --- /dev/null +++ b/upcoming_changelogs/6007.md @@ -0,0 +1,4 @@ +**Bug fixes** + +- Fixed the focus context of `EuiDataGrid` to ensure that focusedCell maintains it's referential integrity. This ensures that React hooks can use this safely as a dependency. +