# react-vtree
**Repository Path**: ALeLe/react-vtree
## Basic Information
- **Project Name**: react-vtree
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: MIT
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2020-04-21
- **Last Updated**: 2020-12-19
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# react-vtree
[](https://www.npmjs.com/package/react-vtree)
[](./LICENSE)
[](https://travis-ci.org/Lodin/react-vtree)
[](https://codecov.io/gh/Lodin/react-vtree)
This package provides a lightweight and flexible solution for rendering large
tree structures. It is built on top of the [react-window](https://github.com/bvaughn/react-window)
library.
**Attention!** This library is entirely rewritten to work with the `react-window`. If
you are looking for the tree view solution for the [react-virtualized](https://github.com/bvaughn/react-virtualized),
take a look at [react-virtualized-tree](https://github.com/diogofcunha/react-virtualized-tree).
## Installation
```bash
# npm
npm i react-window react-vtree
# Yarn
yarn add react-window react-vtree
```
## Usage
### `FixedSizeTree`
#### Example
You can also take a look at the very similar example at the Storybook:
- [Source code](./__stories__/FixedSizeTree.story.tsx)
- [Demo](https://lodin.github.io/react-vtree/index.html?path=/story/tree--fixedsizetree)
```javascript
import {FixedSizeTree as Tree} from 'react-vtree';
// Tree component can work with any possible tree structure because it uses an
// iterator function that the user provides. Structure, approach, and iterator
// function below is just one of many possible variants.
const tree = {
name: 'Root #1',
id: 'root-1',
children: [
{
children: [
{id: 'child-2', name: 'Child #2'},
{id: 'child-3', name: 'Child #3'},
],
id: 'child-1',
name: 'Child #1',
},
{
children: [{id: 'child-5', name: 'Child #5'}],
id: 'child-4',
name: 'Child #4',
},
],
};
function* treeWalker(refresh) {
const stack = [];
// Remember all the necessary data of the first node in the stack.
stack.push({
nestingLevel: 0,
node: tree,
});
// Walk through the tree until we have no nodes available.
while (stack.length !== 0) {
const {
node: {children, id, name},
nestingLevel,
} = stack.pop();
// Here we are sending the information about the node to the Tree component
// and receive an information about the openness state from it. The
// `refresh` parameter tells us if the full update of the tree is requested;
// basing on it we decide to return the full node data or only the node
// id to update the nodes order.
const isOpened = yield refresh
? {
id,
isLeaf: children.length === 0,
isOpenByDefault: true,
name,
nestingLevel,
}
: id;
// Basing on the node openness state we are deciding if we need to render
// the child nodes (if they exist).
if (node.children.length !== 0 && isOpened) {
// Since it is a stack structure, we need to put nodes we want to render
// first to the end of the stack.
for (let i = node.children.length - 1; i >= 0; i--) {
stack.push({
nestingLevel: nestingLevel + 1,
node: node.children[i],
});
}
}
}
}
// Node component receives all the data we created in the `treeWalker` +
// internal openness state (`isOpen`), function to change internal openness
// state (`toggle`) and `style` parameter that should be added to the root div.
const Node = ({data: {isLeaf, name}, isOpen, style, toggle}) => (
{!isLeaf && (
)}
{name}
);
const Example = () => (
{Node}
);
```
#### Props
The component receives all the props of the `FixedSizeList` component except for
the `itemCount`. Additional properties are the following:
##### `children`
The `Node` component that is responsible for rendering each node. It receives
all the properties [`Row`](https://react-window.now.sh/#/api/FixedSizeList)
recieves except for the `index` prop plus the following properties:
- `data: object` - a data object yielded by the `treeWalker` function.
- `isOpen: boolean` - a current openness status of the node.
- `toggle(): function` - a function to change the openness state of the node. It
receives no arguments and can be provided directly as an `onClick` handler.
- `treeData: any` - any data provided via the `itemData` property of the
`FixedSizeTree` component.
##### `rowComponent: component`
This property receives a custom `Row` component for the `FixedSizeList` that
will override the default one. It can be used for adding new functionality to an
existing one by wrapping the default `Row` into a custom component.
##### `* treeWalker(refresh: boolean)`
An iterator function that walks around the tree and yields each node one by one
flattening them to an array that can be easily displayed by `FixedSizeList`
component.
The function receives `refresh` parameter. If it is `true`, the component
requests the full node update and expects the complete data object yielded. If
it is `false`, the component awaits only the node id to update the order of
displayed nodes.
The data object should contain the following required properties:
- `id` - a unique identifier of the node.
- `isOpenByDefault` - a default openness state of the node.
You can add any other property you need. This object will be sent directly to
the `Node` component.
Yielding the object gets the current openness state of the node. Basing on it,
you should decide if the node's children are going to be rendered.
#### Methods
The component provides all the methods `FixedSizeList` provides with the
following changes:
##### `scrollToItem(id: string | symbol, align?: Align): void`
The `scrollToItem` method receives node `id` instead of `index`.
##### `async recomputeTree(options): void`
This method runs the `treeWalker` function again and, basing on the received
options, updates either nodes or their order.
It receives options object with the following parameters:
- `refreshNodes: boolean` - if this parameter is `true`, `treeWalker` will
receive `refresh` option, and the component will expect the data object yielded.
If this parameter is either `false` or not provided, the component will expect
string id.
- `useDefaultOpenness: boolean` - if this parameter is `true`, openness state of
all nodes will be reset to `isOpenByDefault`. Nodes updated during the tree
walking will use the new `isOpenByDefault` value.
### `VariableSizeTree`
#### Example
You can also take a look at the very similar example at the Storybook:
- [Source code](./__stories__/VariableSizeTree.story.tsx)
- [Demo](https://lodin.github.io/react-vtree/index.html?path=/story/tree--variablesizetree)
```javascript
import {VariableSizeTree as Tree} from 'react-vtree';
// Tree component can work with any possible tree structure because it uses an
// iterator function that the user provides. Structure, approach, and iterator
// function below is just one of many possible variants.
const tree = {
name: 'Root #1',
id: 'root-1',
children: [
{
children: [
{id: 'child-2', name: 'Child #2'},
{id: 'child-3', name: 'Child #3'},
],
id: 'child-1',
name: 'Child #1',
},
{
children: [{id: 'child-5', name: 'Child #5'}],
id: 'child-4',
name: 'Child #4',
},
],
};
function* treeWalker(refresh) {
const stack = [];
stack.push({
nestingLevel: 0,
node: tree,
});
while (stack.length !== 0) {
const {
node: {children, id, name},
nestingLevel,
} = stack.pop();
const isOpened = yield refresh
? {
// The only difference VariableSizeTree `treeWalker` has comparing to
// the FixedSizeTree is the `defaultHeight` property in the data
// object.
defaultHeight: 30,
id,
isLeaf: children.length === 0,
isOpenByDefault: true,
name,
nestingLevel,
}
: id;
if (node.children.length !== 0 && isOpened) {
for (let i = node.children.length - 1; i >= 0; i--) {
stack.push({
nestingLevel: nestingLevel + 1,
node: node.children[i],
});
}
}
}
}
// Node component receives current node height as a prop
const Node = ({data: {isLeaf, name}, height, isOpen, style, toggle}) => (
{!isLeaf && (
)}
{name}
);
const Example = () => (
{Node}
);
```
#### Props
The component receives all the props of the `VariableSizeList` component except
for the `itemCount` and `itemSize`. `itemSize` is still available but not
required, and should be used only if the default behavior is not enough.
Additional properties are the following:
##### `children`
The `Node` component. It is the same as the [`FixedSizeTree`](#fixedsizetree)'s
one but receives two additional properties:
- `height: number` - a current height of the node.
- `resize(newHeight: number, shouldForceUpdate?: boolean): function` - a
function to change the height of the node. It receives two parameters:
- `newHeight: number` - a new height of the node.
- `shouldForceUpdate: boolean` - an optional argument that will be sent to the
[`resetAfterIndex`](https://react-window.now.sh/#/api/VariableSizeList)
method.
##### `rowComponent: component`
This property receives a custom `Row` component for the `VariableSizeList` that
will override the default one. It can be used for adding new functionality to an
existing one by wrapping the default `Row` into a custom component.
##### `* treeWalker(refresh: boolean)`
An iterator function that walks over the tree. It behaves the same as
`FixedSizeTree`'s `treeWalker`, but there one additional required property for
the data object:
- `defaultHeight: number` - the default height of the node.
#### Methods
The component provides all the methods `VariableSizeList` provides with the
following changes:
##### `scrollToItem(id: string | symbol, align?: Align): void`
The `scrollToItem` method receives node `id` instead of `index`.
##### `resetAfterId(id: string | symbol, shouldForceUpdate: boolean = false): void`
This method replaces the `resetAfterIndex` method of `VariableSizeList`, but
works exactly the same. It receives node `id` as a first argument.
##### `async recomputeTree(options): void`
This method works exactly the same as the `FixedSizeTree`'s one, but receives
one additional option:
- `useDefaultHeight: boolean` - if this parameter is `true`, the height of
all nodes will be reset to `defaultHeight`. Nodes updated during the tree
walking will use the new `defaultHeight` value.