-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(useTable): selection manager to avoid calling multiple hooks (#2…
…4377) * feat(useTable): selection manager to avoid calling multiple hooks Implements a `createSelectionManager` function to manage selection state independently of react and avoids calling state hooks twice on each render * changefile * pr suggestions * add node env test * deSelect to deselect * update md
- Loading branch information
Showing
14 changed files
with
554 additions
and
516 deletions.
There are no files selected for viewing
7 changes: 7 additions & 0 deletions
7
change/@fluentui-react-table-8af09ced-5374-4d8e-ab4f-6fd3d444e0e6.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"type": "prerelease", | ||
"comment": "refactor(useTable): selection manager to avoid calling multiple hooks", | ||
"packageName": "@fluentui/react-table", | ||
"email": "[email protected]", | ||
"dependentChangeType": "patch" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
113 changes: 113 additions & 0 deletions
113
packages/react-components/react-table/src/hooks/selectionManager.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
import { SelectionMode } from './types'; | ||
|
||
type OnSelectionChangeCallback = (selectedItems: Set<SelectionItemId>) => void; | ||
|
||
export interface SelectionManager { | ||
toggleItem(id: SelectionItemId): void; | ||
selectItem(id: SelectionItemId): void; | ||
deselectItem(id: SelectionItemId): void; | ||
clearItems(): void; | ||
isSelected(id: SelectionItemId): boolean; | ||
toggleAllItems(itemIds: SelectionItemId[]): void; | ||
} | ||
|
||
export type SelectionItemId = string | number; | ||
|
||
export function createSelectionManager( | ||
mode: SelectionMode, | ||
onSelectionChange: OnSelectionChangeCallback = () => undefined, | ||
): SelectionManager { | ||
const managerFactory = mode === 'multiselect' ? createMultipleSelectionManager : createSingleSelectionManager; | ||
|
||
return managerFactory(onSelectionChange); | ||
} | ||
|
||
function createMultipleSelectionManager(onSelectionChange: OnSelectionChangeCallback): SelectionManager { | ||
const selectedItems = new Set<SelectionItemId>(); | ||
const toggleAllItems = (itemIds: SelectionItemId[]) => { | ||
const allItemsSelected = itemIds.every(itemId => selectedItems.has(itemId)); | ||
|
||
if (allItemsSelected) { | ||
selectedItems.clear(); | ||
} else { | ||
itemIds.forEach(itemId => selectedItems.add(itemId)); | ||
} | ||
|
||
onSelectionChange(new Set(selectedItems)); | ||
}; | ||
|
||
const toggleItem = (itemId: SelectionItemId) => { | ||
if (selectedItems.has(itemId)) { | ||
selectedItems.delete(itemId); | ||
} else { | ||
selectedItems.add(itemId); | ||
} | ||
|
||
onSelectionChange(new Set(selectedItems)); | ||
}; | ||
|
||
const selectItem = (itemId: SelectionItemId) => { | ||
selectedItems.add(itemId); | ||
onSelectionChange(new Set(selectedItems)); | ||
}; | ||
|
||
const deselectItem = (itemId: SelectionItemId) => { | ||
selectedItems.delete(itemId); | ||
onSelectionChange(new Set(selectedItems)); | ||
}; | ||
|
||
const clearItems = () => { | ||
selectedItems.clear(); | ||
onSelectionChange(new Set(selectedItems)); | ||
}; | ||
|
||
const isSelected = (itemId: SelectionItemId) => { | ||
return selectedItems.has(itemId); | ||
}; | ||
|
||
return { | ||
toggleItem, | ||
selectItem, | ||
deselectItem, | ||
clearItems, | ||
isSelected, | ||
toggleAllItems, | ||
}; | ||
} | ||
|
||
function createSingleSelectionManager(onSelectionChange: OnSelectionChangeCallback): SelectionManager { | ||
let selectedItem: SelectionItemId | undefined = undefined; | ||
const toggleItem = (itemId: SelectionItemId) => { | ||
selectedItem = itemId; | ||
onSelectionChange(new Set([selectedItem])); | ||
}; | ||
|
||
const clearItems = () => { | ||
selectedItem = undefined; | ||
onSelectionChange(new Set<SelectionItemId>()); | ||
}; | ||
|
||
const isSelected = (itemId: SelectionItemId) => { | ||
return selectedItem === itemId; | ||
}; | ||
|
||
const selectItem = (itemId: SelectionItemId) => { | ||
selectedItem = itemId; | ||
onSelectionChange(new Set([selectedItem])); | ||
}; | ||
|
||
return { | ||
deselectItem: clearItems, | ||
selectItem, | ||
toggleAllItems: () => { | ||
if (process.env.NODE_ENV !== 'production') { | ||
throw new Error('[react-table]: `toggleAllItems` should not be used in single selection mode'); | ||
} | ||
|
||
return undefined; | ||
}, | ||
toggleItem, | ||
clearItems, | ||
isSelected, | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.