npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@hleote/react-vtree

v3.0.0-beta.5

Published

React component for efficiently rendering large tree structures

Downloads

6

Readme

react-vtree

Latest Stable Version License CI Status Coverage Bugs Vulnerabilities

This package provides a lightweight and flexible solution for rendering large tree structures. It is built on top of the 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, take a look at react-virtualized-tree.

Installation

# 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:

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 (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 = children.length - 1; i >= 0; i--) {
        stack.push({
          nestingLevel: nestingLevel + 1,
          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}) => (
  <div style={style}>
    {!isLeaf && (
      <button type="button" onClick={toggle}>
        {isOpen ? '-' : '+'}
      </button>
    )}
    <div>{name}</div>
  </div>
);

const Example = () => (
  <Tree treeWalker={treeWalker} itemSize={30} height={150} width={300}>
    {Node}
  </Tree>
);

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 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:

  • opennessState: Record<string, boolean> - nodes whose IDs are specified as keys of this object will be opened or closed according to boolean values. If the value is true, node will be opened; otherwise, it will be closed. This object can be used for changing nodes' openness programmatically without re-creating the treeWalker generator.

    NOTE: If you specify both useDefaultOpenness and opennessState, opennessState will be overridden by useDefaultOpenness results.

  • 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.

Types

  • FixedSizeNodeData - object the treeWalker generator function yields for each new node. By default, it contains only id and isOpenByDefault fields, but you can add any number of additional fields; they will be sent directly to the Node component. To describe that data, you have to create a new type that extends the FixedSizeNodeData type.
  • FixedSizeNodeComponentProps<T extends FixedSizeNodeData> - props that Node component receives. They are described in the Props children section.
  • FixedSizeTreeProps<T extends FixedSizeNodeData> - props that FixedSizeTree component receives. Described in the Props section.
  • FixedSizeTreeState<T extends FixedSizeNodeData> - state that FixedSizeTree component has.

VariableSizeTree

Example

You can also take a look at the very similar example at the Storybook:

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 (children.length !== 0 && isOpened) {
      for (let i = children.length - 1; i >= 0; i--) {
        stack.push({
          nestingLevel: nestingLevel + 1,
          node: children[i],
        });
      }
    }
  }
}

// Node component receives current node height as a prop
const Node = ({data: {isLeaf, name}, height, isOpen, style, toggle}) => (
  <div style={style}>
    {!isLeaf && (
      <button type="button" onClick={toggle}>
        {isOpen ? '-' : '+'}
      </button>
    )}
    <div>{name}</div>
  </div>
);

const Example = () => (
  <Tree treeWalker={treeWalker} height={150} width={300}>
    {Node}
  </Tree>
);

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'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 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.

Types

All types in this section are the extended variants of FixedSizeTree types.

  • VariableSizeNodeData
  • VariableSizeNodeComponentProps<T extends VariableSizeNodeData>.
  • VariableSizeTreeProps<T extends VariableSizeNodeData>.
  • VariableSizeTreeState<T extends VariableSizeNodeData>.