Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DataGrid] Ensure referential integrity of focused cell #6007

Merged
merged 9 commits into from
Jul 4, 2022
16 changes: 11 additions & 5 deletions src/components/datagrid/utils/focus.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand Down
20 changes: 16 additions & 4 deletions src/components/datagrid/utils/focus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<EuiDataGridFocusedCell | undefined>(undefined);
useEffect(() => {
Expand Down
4 changes: 4 additions & 0 deletions upcoming_changelogs/6007.md
Original file line number Diff line number Diff line change
@@ -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.
cee-chen marked this conversation as resolved.
Show resolved Hide resolved