Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tree fails to render or appear in DOM #407

Closed
ck-cklinger opened this issue Aug 8, 2024 · 10 comments
Closed

Tree fails to render or appear in DOM #407

ck-cklinger opened this issue Aug 8, 2024 · 10 comments
Assignees

Comments

@ck-cklinger
Copy link

Describe the bug

Starting off with this library (this is great by the way, thank you for creating and maintaining this library), so attempting to start pretty basic and then adapt it to my specific needs. I have a component that should hold the tree:

import {
  UncontrolledTreeEnvironment,
  StaticTreeDataProvider,
  Tree,
} from "react-complex-tree";

const CategoryTree = () => {
  const readTemplate = (template: any, data: any = { items: {} }): any => {
    for (const [key, value] of Object.entries(template)) {
      // eslint-disable-next-line no-param-reassign
      data.items[key] = {
        index: key,
        canMove: true,
        isFolder: value !== null,
        children:
          value !== null ? Object.keys(value as Record<string, unknown>) : [],
        // : undefined,
        data: key,
        canRename: true,
      };

      if (value !== null) {
        readTemplate(value, data);
      }
    }
    return data;
  };

  const categoryItems = {
    root: {
      container: {
        item0: null,
        item1: null,
        item2: null,
        item3: {
          inner0: null,
          inner1: null,
          inner2: null,
          inner3: null,
        },
        item4: null,
        item5: null,
      },
    },
  };

  const items = readTemplate(categoryItems);
  console.log(items);

  return (
    <UncontrolledTreeEnvironment
      dataProvider={
        new StaticTreeDataProvider(items, (item, data) => ({
          ...item,
          data,
        }))
      }
      getItemTitle={(item) => item.data}
      viewState={{
        "tree-1": {
          expandedItems: [],
        },
      }}
    >
      <Tree treeId="tree-1" rootItem="root" treeLabel="Test" />
    </UncontrolledTreeEnvironment>
  );
};

export default CategoryTree;

This is basically ripped straight from the docs/example code in the source files, so I would expect it would work.

The issue I'm running into is that the Tree component does not render (I have another parent component that includes <CategoryTree /> as one of its children). There's no error in the console and no flags in my IDE, but it doesn't show up in my browser and I also can't find it in the DOM at all.

Expected behavior

I would expect to see something similar to here: https://rct.lukasbach.com/docs/guides/static-data-provider

Additional context

Currently running in a dev environment using:

  • Vite version 5.2.0
  • React version 18.2.66
  • React complex tree version 2.4.5

Running in Chrome version 127.0.6533.89 on Mac OS Venture (13.0)

I'm happy to provide any other information that may help in figuring this out. I'm probably just doing something dumb and this isn't actually a bug, but I can't be sure of that at the moment.

@ck-cklinger
Copy link
Author

With some slight code changes, I now have a version of it working - still not sure why this original code would not render anything though...

@TCXX
Copy link

TCXX commented Sep 28, 2024

How did you solve it?

@alzeebum
Copy link
Contributor

alzeebum commented Jan 1, 2025

Having essentially the same problem. Any insight into how you solved it @ck-cklinger ? Or you @TCXX ?

The tree simply doesn't render. No warnings, errors, or other information in either the vite output or the browser debug console, just.. nothing.

@alzeebum
Copy link
Contributor

alzeebum commented Jan 2, 2025

So in my case it turns out I am getting some output in the DOM, but nothing in the tree, using this data structure:

  const initialTreeData = {
    doc: {
      index: 'doc',
      canMove: false,
      isFolder: true,
      canRename: true,
      children: ['c1', 'c2'],
      data: 'root'
    },
    ch1: {
      index: 'c1',
      canMove: true,
      isFolder: true,
      canRename: true,
      children: ['s1', 's2'],
      data: 'chapter 1'
    },
    ch2: {
      index: 'c2',
      canMove: true,
      isFolder: true,
      canRename: true,
      children: [],
      data: 'chapter 2'
    },
    s1: {
      index: 's1',
      canMove: true,
      isFolder: false,
      canRename: true,
      children: [],
      data: 'scene 1'
    },
    s2: {
      index: 's2',
      canMove: true,
      isFolder: false,
      canRename: true,
      children: [],
      data: 'Scene 2'
    }
  };

  const dataProvider = new StaticTreeDataProvider(initialTreeData, (item, newName) => ({ ...item, data: newName}));

And this return value for the component (App right now for testing):

  return (
          <UncontrolledTreeEnvironment
            dataProvider={dataProvider}
            getItemTitle={item => item.data}
            viewState={{}}
            canDragAndDrop={true}
            canDropOnFolder={true}
            canReorderItems={true}
          >
            <Tree treeId='tree-1' rootItem='doc' treeLabel='Document' />
          </UncontrolledTreeEnvironment>
  );

However the list for the tree is entirely empty, though the aria stuff is there. I've clipped all the css and scripting out of 'head' for brevity as it's over 8000 lines (also using mantine UI):

<html lang="en"><head>
</head>

  <body data-bs-theme="light">
    <div id="root"><div class="rct-tree-root"><div role="tree" aria-label="Document" data-rct-tree="tree-1" style="min-height: 30px; position: relative;"><div id="rct-livedescription-tree-1" style="clip: rect(0px, 0px, 0px, 0px); clip-path: inset(50%); height: 1px; overflow: hidden; position: absolute; white-space: nowrap; width: 1px;"><div aria-live="off">
    <p>Accessibility guide for tree Document.</p>
    <p>
      Navigate the tree with the arrow keys. Common tree hotkeys apply. Further keybindings are available:
    </p>
    <ul>
      <li>enter to execute primary action on focused item</li>
      <li>f2 to start renaming the focused item</li>
      <li>escape to abort renaming an item</li>
      <li>control+d to start dragging selected items</li>
    </ul>
  </div></div><ul class="rct-tree-items-container"></ul></div></div></div>
    <script type="module" src="/src/main.jsx"></script>
  

</body></html>

The main issue seems to be this: <ul class="rct-tree-items-container"></ul> near the bottom. No tree is being output from the supplied data.

@alzeebum
Copy link
Contributor

alzeebum commented Jan 2, 2025

Ok, for me, solved. I mistakenly thought the index field was what children refers to, but it's the key in the data structure. Seems to be working now.

EDIT:

The full story actually seems to be that, when using the uncontrolled environment with a simple StaticTreeDataProvider as in the example, the object key and it's index property must match. This isn't documented and I don't know why it's the case, but it is.

I could not find a repo for the docs so I can't submit a PR to change them to mention this behavior.

@lukasbach
Copy link
Owner

Thanks for pointing that out @alzeebum, yes that is in fact not explicitly mentioned in the docs. If you would like to contribute that part to the docs yourself, feel free to do so, they are located here: https://github.com/lukasbach/react-complex-tree/tree/main/packages/docs/docs
Otherwise, I can also add a mention in the docs on that.

@and-sm
Copy link

and-sm commented Jan 11, 2025

@lukasbach can you please provide an example? The structure below doesn't solve the problem.

key: {
      index: key,
      canMove: true,
      isFolder: false,
      children: undefined,
      data: 'text',
      canRename: true
    }

@ck-cklinger
Copy link
Author

Ok, for me, solved. I mistakenly thought the index field was what children refers to, but it's the key in the data structure. Seems to be working now.

EDIT:

The full story actually seems to be that, when using the uncontrolled environment with a simple StaticTreeDataProvider as in the example, the object key and it's index property must match. This isn't documented and I don't know why it's the case, but it is.

I could not find a repo for the docs so I can't submit a PR to change them to mention this behavior.

It's been a long time, but I believe the issue I was having was this.

I've since changed my entire implementation to use a ControlledTreeEnvironment but still begin with a StaticTreeDataProvider that I manually push items to.

The basic bones of it are:

  const defaultItems = (): Record<TreeItemIndex, TreeItem> => {
    return {
      root: {
        index: "root",
        isFolder: true,
        children: [],
        data: {
          id: 0,
          (other fields here)
        },
      },
    };
  };

  const items: Record<TreeItemIndex, TreeItem<Category>> = useMemo(() => {
    return defaultItems();
  }, []);

  const dataProvider = useMemo(
    () =>
      new StaticTreeDataProvider(items, (item) => ({
        ...item,
      })),
    [items]
  );

I believe the important detail (if memory serves - I haven't looked at this in a while) is that your TreeItem objects need an "index" attribute, and this is what needs to be used for any node's children array. In my case, I use the same value for the "id" in the actual object and the TreeItem index.

@lukasbach
Copy link
Owner

@ck-cklinger I btw. noticed another issue in the code you posted in your initial post, though I guess you figured that out by now:

    new StaticTreeDataProvider(items, (item, data) => ({
      ...item,
      data,
    }))

It should be StaticTreeDataProvider(items.items, .... instead, the items variable in your code was itself of the structure { items: { itemKey: {...} }}, but the parameter of StaticTreeDataProvider itself takes a record that directly maps item keys to item objects. Just in case this is also related to the issue you had @and-sm.

This is a subset of the sample data structure used in the RCT examples:

{
    "root": {
      "index": "root",
      "canMove": true,
      "isFolder": true,
      "children": [
        "Fruit",
        "Meals",
        "Desserts",
        "Drinks"
      ],
      "data": "root",
      "canRename": true
    },
    "Fruit": {
      "index": "Fruit",
      "canMove": true,
      "isFolder": true,
      "children": [
        "Apple",
        "Orange",
        "Lemon",
        "Berries",
        "Banana"
      ],
      "data": "Fruit",
      "canRename": true
    },
    "Apple": {
      "index": "Apple",
      "canMove": true,
      "isFolder": false,
      "data": "Apple",
      "canRename": true
    },
    "Orange": {
      "index": "Orange",
      "canMove": true,
      "isFolder": false,
      "data": "Orange",
      "canRename": true
    }
...

@ck-cklinger
Copy link
Author

@lukasbach thanks for pointing that out! I think, with the additions to the documentation (thanks @alzeebum) and this clarification it would make sense to close this issue now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants