|
| 1 | +# react-vtree |
| 2 | + |
| 3 | +This component is designed as a basic solution for rendering huge tree structures without affecting performance. Under |
| 4 | +the hood it uses [react-virtualized](https://github.com/bvaughn/react-virtualized) library and also can be considered |
| 5 | +as a part of this library. |
| 6 | + |
| 7 | +### Terminology |
| 8 | +* **Node** - basic structure element of tree. Nodes nested in each other form tree structure. |
| 9 | +* **Row** - single line of virtualized list that contains one node and a margin showing nesting level of the node. Row |
| 10 | +can also contain a button to toggle visibility of the node's children. |
| 11 | + |
| 12 | +### Prop Types |
| 13 | +| Property | Type | Required? | Description | |
| 14 | +|----------|----------|:--------:|----------| |
| 15 | +| autoHeight | Boolean | | Removes fixed height from the `scrollingContainer` so that the total height of rows can stretch the window. Intended for use with `WindowScroller` HOC. | |
| 16 | +| className | String | | Optional CSS class name. | |
| 17 | +| controlClassName | String | | Optional CSS class for all toggle controls. | |
| 18 | +| controlStyle | Object | | Optional inline styles for all toggle controls. | |
| 19 | +| estimatedRowSize | Number | | Used to estimate the total height of a Tree before all of its rows have actually been measured. The estimated total height is adjusted as rows are rendered. | |
| 20 | +| height | Number | ✓ | Sets height of a container Tree is rendered inside of. It also determines how many actual rows are rendered. | |
| 21 | +| id | String | | Custom HTML id | |
| 22 | +| nodeGetter | Function | ✓ | Generator flattens tree data to display it in a list form basing on information of nodes' openness. It should yield node metadata or node id depending on boolean `refresh` parameter it receives. | |
| 23 | +| nodeNestingMultiplier | Number | | Multiplier for a margin that depends on node's nesting level. E.g. if multiplier is 10 margin for node with nesting level 2 will be 20px and for node with nesting level 3 - 30px. | |
| 24 | +| noRowsRenderer | Function | | Optional renderer to be used in place of rows when tree is empty. | |
| 25 | +| onRowClick | Function | | Callback invoked when a user clicks on a node | |
| 26 | +| onRowDoubleClick | Function | | Callback invoked when a user double-clicks on a node | |
| 27 | +| onRowMouseOut | Function | | Callback invoked when the mouse leaves a node | |
| 28 | +| onRowMouseOver | Function | | Callback invoked when a user moves the mouse over a node | |
| 29 | +| onRowRightClick | Function | | Callback invoked when a user right-clicks on a node | |
| 30 | +| onRowsRendered | Function | | Callback invoked with information about the slice of rows that were just rendered | |
| 31 | +| onScroll | Function | | Callback invoked whenever the scroll offset changes within the inner scrollable region. This callback can be used to sync scrolling between lists, tables, or grids. | |
| 32 | +| overscanIndicesGetter | Object | | See Grid#overscanIndicesGetter. | |
| 33 | +| overscanRowCount | Number | | Number of rows to render above/below the visible bounds of the list. These rows can help for smoother scrolling on touch devices. | |
| 34 | +| rowClassName | String | | Optional CSS class to apply to all rows. | |
| 35 | +| rowHeight | Number | ✓ | Fixed row height. | |
| 36 | +| rowRenderer | Function | | Renders data received from NodeGetter. | |
| 37 | +| rowStyle | Object | | Optional inline styles for all rows. | |
| 38 | +| scrollToAlignment | String | | See Grid#scrollToAlignment | |
| 39 | +| scrollToIndex | Number | | Row index to ensure visible (by forcefully scrolling if necessary). | |
| 40 | +| scrollTop | Number | | Vertical offset. | |
| 41 | +| style | Object | | Optional inline styles. | |
| 42 | +| tabIndex | Number | | Tab index for focus. | |
| 43 | +| update | Number | | If is set and is different than Update.None forces component to recompute and call nodeGetter. This property is not pure: component will re-render any time it receives this property and it is not Update.None. Useful if you changed something in the tree structure and want to re-render component using new data. | |
| 44 | +| width | Number | ✓ | Width of Tree container. | |
| 45 | + |
| 46 | +### Public Methods |
| 47 | + |
| 48 | +#### forceUpdateGrid (callback?: () => any) |
| 49 | +Forcefully re-render the inner `Grid` component. |
| 50 | + |
| 51 | +Calling `forceUpdate` on `Tree` may not re-render the inner `Grid` since it uses `shallowCompare` as a performance |
| 52 | +optimization. Use this method if you want to manually trigger a re-render. This may be appropriate if the underlying |
| 53 | +row data has changed but the row sizes themselves have not. |
| 54 | + |
| 55 | +#### getOffsetForRow (params: {alignment?: string, index?: number}): number |
| 56 | +Gets offset for a given row and alignment. |
| 57 | + |
| 58 | +#### measureAllRows (): void |
| 59 | +Pre-measure all rows in a `Tree`. |
| 60 | + |
| 61 | +Typically rows are only measured as needed and estimated heights are used for cells that have not yet been measured. |
| 62 | +This method ensures that the next call to getTotalSize() returns an exact size (as opposed to just an estimated one). |
| 63 | + |
| 64 | +#### recomputeTree (update: Update): Promise<void> |
| 65 | +Recomputes Tree component basing on update type. |
| 66 | + |
| 67 | +Method calls `nodeGetter` internally and flattens tree structure to an array. Depending on `update` value it runs |
| 68 | +one of the following algorithms: |
| 69 | + 1) **Update.NodesAndOpenness**. Requires full node metadata. Updates order, number and rendering data of all |
| 70 | + nodes. Overrides current openness state with `openedByDefault` value. |
| 71 | + 2) **Update.Nodes**. Requires full node metadata. Updates order, number and rendering data of all nodes. Preserves |
| 72 | + openness state of all nodes. |
| 73 | + 3) **Update.Order**. Requires only node id. Updates nodes order (useful for sorting etc.). Preserves openness |
| 74 | + state of all nodes. |
| 75 | + 4) **Update.None**. Updates nothing. |
| 76 | + |
| 77 | +After all computations forces inner `Grid` to re-render. Returns promise that resolves after all re-rendering is done. |
| 78 | + |
| 79 | +#### scrollToPosition (scrollTop: number): void |
| 80 | +Scroll to the specified offset. |
| 81 | +Useful for animating position changes. |
| 82 | + |
| 83 | +#### scrollToRow (index: number): void |
| 84 | +Ensure row is visible. |
| 85 | +This method can be used to safely scroll back to a cell that a user has scrolled away from even if it was previously |
| 86 | +scrolled to. |
| 87 | + |
| 88 | +### nodeGetter (refresh: boolean): IterableIterator<Node | string | null> |
| 89 | +This callback is responsible for providing tree data in consumable form. It should be a `generator` that yields node |
| 90 | +metadata to render. Depending on `refresh` parameter it should yield full metadata or only node id. The result of |
| 91 | +yielding will be current openness state of the node. This value should be used as a rule to decide if `nodeGetter` |
| 92 | +should render node's children or not. |
| 93 | + |
| 94 | +#### Node |
| 95 | +| Property | Type | Can be omitted? | Description | |
| 96 | +|----------|----------|:--------:|----------| |
| 97 | +| childrenCount | Number | | Number of current node children. | |
| 98 | +| id | String | | Unique ID of current node. Used to identify node inside Tree component. | |
| 99 | +| height | Number | ✓ | Current node height. Specify only if you want your tree to have nodes with different heights. | |
| 100 | +| isOpenedByDefault | Boolean | | Current node openness state. Will set node openness state on first rendering or if `update` is set to Update.NodeAndOpenness. | |
| 101 | +| nestingLevel | Number | | Current node nesting level (how deep it is placed relative to tree root). | |
| 102 | +| nodeData | Any | | Node data to be rendered. Will be sent as is to `rowRenderer` callback. | |
| 103 | +| style | Object | ✓ | Specific styles for row contains current node. | |
| 104 | + |
| 105 | +#### Example |
| 106 | +Let's imagine our tree is build from following nodes: |
| 107 | +```typescript |
| 108 | +interface TreeNode { |
| 109 | + id: string; |
| 110 | + name: string; |
| 111 | + children: TreeNode[]; |
| 112 | +} |
| 113 | +``` |
| 114 | +Then `nodeGetter` for this tree could be following: |
| 115 | +```typescript |
| 116 | +function * nodeGetter(refresh: boolean): IterableIterator<Node | string | null> { |
| 117 | + const stack = []; |
| 118 | + |
| 119 | + stack.push({ |
| 120 | + nestingLevel: 0, |
| 121 | + node: root, // tree data structure |
| 122 | + }); |
| 123 | + |
| 124 | + while (stack.length !== 0) { |
| 125 | + const {node, nestingLevel} = stack.pop()!; |
| 126 | + const id = node.id.toString(); |
| 127 | + |
| 128 | + const isOpened = yield ( |
| 129 | + refresh ? { |
| 130 | + childrenCount: node.children.length, |
| 131 | + height: 20, // only if you want to use dynamic heights; otherwise use "rowHeight" |
| 132 | + id, |
| 133 | + isOpenedByDefault: true, // set "true" if you want your tree to be opened by default, or "false" if you want it closed |
| 134 | + nestingLevel, |
| 135 | + nodeData: node.name, |
| 136 | + } : id |
| 137 | + ); |
| 138 | + |
| 139 | + if (node.children.length !== 0 && isOpened) { |
| 140 | + for (let i = node.children.length - 1; i >= 0; i--) { |
| 141 | + stack.push({ |
| 142 | + nestingLevel: nestingLevel + 1, |
| 143 | + node: node.children[i], |
| 144 | + }); |
| 145 | + } |
| 146 | + } |
| 147 | + } |
| 148 | +} |
| 149 | +``` |
| 150 | + |
| 151 | +### rowRenderer (params: RowRendererParams): React.ReactNode |
| 152 | +This callback is responsible for rendering single tree row. It receives metadata including data from `nodeGetter` and |
| 153 | +renders it to a React node. |
| 154 | + |
| 155 | +Default tree renderer can provide only the very basic tree rendering: toggle button and string body. So if you need |
| 156 | +more functional tree, you can fork `defaultRowRenderer`. |
| 157 | + |
| 158 | + |
| 159 | +#### RowRendererParams |
| 160 | +| Property | Type | Can be undefined? | Description | |
| 161 | +|----------|----------|:--------:|----------| |
| 162 | +| childrenCount | Number | | Number of children current node has. | |
| 163 | +| className | String | ✓ | Optional CSS class name (a `rowClassName` property set in Tree component). | |
| 164 | +| controlClassName | String | ✓ | Optional CSS class name for toggle control (a `controlClassName` property set in Tree component). | |
| 165 | +| controlStyle | Object | | Inline styles for toggle control. Contains two styles: 1) a `controlStyle` property set in Tree component, 2) default styles necessary for displaying control | |
| 166 | +| id | String | | Optional HTML id (an `id` property set in Tree component). | |
| 167 | +| index | Number | | Current row index in the list of all rows. | |
| 168 | +| isOpened | Boolean | | Current node openness state. | |
| 169 | +| isScrolling | Boolean | | Current row scrolling state. | |
| 170 | +| key | String | | Unique key to specify current row. Should be sent to row container to avoid re-rendering issues. | |
| 171 | +| nestingLevel | Number | | Current node nesting level (how deep it is placed relative to tree root). | |
| 172 | +| nodeData | Any | | Node data to be rendered. | |
| 173 | +| onNodeToggle | Function | | Callback to control node toggling. Should be sent to control element (e.g. `<button>`) to show and hide node children. | |
| 174 | +| onRowClick | Function | ✓ | Callback invoked when a user clicks on a node (a `onRowClick` property set in Tree component). | |
| 175 | +| onRowDoubleClick | Function | ✓ | Callback invoked when a user double-clicks on a node (a `onRowDoubleClick` property set in Tree component). | |
| 176 | +| onRowMouseOut | Function | ✓ | Callback invoked when the mouse leaves a node (a `onRowMouseOut` property set in Tree component). | |
| 177 | +| onRowMouseOver | Function | ✓ | Callback invoked when a user moves the mouse over a node (a `onRowMouseOver` property set in Tree component). | |
| 178 | +| onRowRightClick | Function | ✓ | Callback invoked when a user right-clicks on a node (a `onRowRightClick` property set in Tree component). | |
| 179 | +| style | Object | | Inline styles for row container. Should be sent to a row container to display tree structure property. Contains tree styles: 1) Styles provided by Grid necessary to display row as an element of Grid. 2) Default row styles provided by Tree component. 3) Row styles provided by `rowStyle` prop from Tree component. 4) Row styles provided by `style` property of metadata gotten from `nodeGetter`. | |
| 180 | + |
| 181 | +### Example |
| 182 | +You can find very basic example in the [stories](./__stories__/Tree.tsx). |
0 commit comments