Created
June 18, 2024 10:17
-
-
Save zourdyzou/438b6fde23420466da600fbc42bed70e to your computer and use it in GitHub Desktop.
This file contains hidden or 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
| import { useMemo, useState } from 'react'; | |
| /** | |
| * A type that extends the generic type T to include a children property. | |
| */ | |
| type TreeNode<T> = T & { [key: string]: any; children?: TreeNode<T>[] }; | |
| /** | |
| * Options for configuring the useTreeFormatData hook. | |
| * | |
| * @property {string} [childrenKey='children'] - The key to access children nodes in the data. | |
| * @property {string} [parentIdKey='parentId'] - The key to access the parent ID in the data. | |
| */ | |
| interface UseTreeFormatDataOptions { | |
| childrenKey?: string; | |
| parentIdKey?: string; | |
| } | |
| /** | |
| * A hook to format a flat data array into a tree structure. | |
| * | |
| * @template T - The type of the data elements. | |
| * @param {T[]} data - The flat data array to be transformed into a tree structure. | |
| * @param {UseTreeFormatDataOptions} options - Configuration options for the tree structure. | |
| * @returns {TreeNode<T>[]} The data array transformed into a tree structure. | |
| */ | |
| export function useTreeFormatData<T>( | |
| data: T[], | |
| options: UseTreeFormatDataOptions = {}, | |
| ): TreeNode<T>[] { | |
| const { childrenKey = 'children', parentIdKey = 'parentId' } = options; | |
| const [dataCopy] = useState(() => JSON.parse(JSON.stringify(data)) as T[]); | |
| const formatTreeData = (data: T[]): TreeNode<T>[] => { | |
| const tree: TreeNode<T>[] = []; | |
| const listId = data.map((item) => (item as any).id); | |
| data.forEach((item) => { | |
| if ( | |
| (item as any)[parentIdKey] !== null && | |
| !listId.includes((item as any)[parentIdKey]) | |
| ) { | |
| (item as any)[parentIdKey] = null; | |
| } | |
| }); | |
| data.sort((a, b) => | |
| (a as any).name | |
| .toLowerCase() | |
| .localeCompare((b as any).name.toLowerCase()), | |
| ); | |
| const dataWithChildren = data.map((item) => ({ | |
| ...item, | |
| [childrenKey]: [], | |
| })) as TreeNode<T>[]; | |
| dataWithChildren.forEach((item) => { | |
| if ((item as any)[parentIdKey] === null) { | |
| tree.push(item); | |
| } else { | |
| const parent = dataWithChildren.find( | |
| (d) => (d as any).id === (item as any)[parentIdKey], | |
| ); | |
| if (parent) { | |
| (parent[childrenKey] as TreeNode<T>[]).push(item); | |
| } | |
| } | |
| }); | |
| return tree; | |
| }; | |
| return useMemo(() => formatTreeData(dataCopy), [dataCopy]); | |
| } | |
| /** | |
| * Usage Example: | |
| * | |
| * const groupData: GroupData[] = [ | |
| * { id: '1', name: 'Group 1', rootGroup: true, subGroups: [] }, | |
| * { id: '2', name: 'Group 2', parentGroupId: '1', subGroups: [] }, | |
| * { id: '3', name: 'Group 3', parentGroupId: '1', subGroups: [] }, | |
| * ]; | |
| * | |
| * const options = { childrenKey: 'subGroups', parentIdKey: 'parentGroupId' }; | |
| * | |
| * const tree = useTreeFormat<GroupData>(groupData, options); | |
| */ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment