lukasbach / react-complex-tree

Unopinionated Accessible Tree Component with Multi-Select and Drag-And-Drop
https://rct.lukasbach.com
MIT License
944 stars 74 forks source link

Unable to update tree data using custom Data Provider #281

Closed paulfedory closed 1 year ago

paulfedory commented 1 year ago

Hello, I'm having some difficulty adding a new node to a tree. I'm using an uncontrolled environment, and a custom data provider, based on the example laid out here.

I've added a new function to my custom data provider called resetData which, like the constructor, takes in items and sets the data property. I'm calling this function at the right time and with logging, I can see that the correct data is being set. The tree does not update after calling this new function.

Is this how I'm supposed to be changing the data for a tree? Should I be constructing a new data provider every time I need to pass in new data?

Below is the code for my data provider:

import {
  Disposable,
  ExplicitDataSource,
  TreeDataProvider,
  TreeItem,
  TreeItemIndex
} from 'react-complex-tree'

export default class CustomDataProvider<T = any> implements TreeDataProvider {
  private data: ExplicitDataSource

  private handlers: Record<string, (changedItemIds: TreeItemIndex[]) => void> = {};

  private setItemName?: (item: TreeItem<T>, newName: string) => TreeItem<T>

  constructor(
    items: Record<TreeItemIndex, TreeItem<T>>,
    setItemName?: (item: TreeItem<T>, newName: string) => TreeItem<T>
  ) {
    this.data = { items }
    this.setItemName = setItemName
  }

  public async getTreeItem(itemId: TreeItemIndex): Promise<TreeItem> {
    return this.data.items[itemId]
  }

  public async onChangeItemChildren(
    itemId: TreeItemIndex,
    newChildren: TreeItemIndex[]
  ): Promise<void> {
    this.data.items[itemId].children = newChildren
    this.data.items[itemId].isFolder = (newChildren.length > 0)
    Object.values(this.handlers).forEach(handler => handler([itemId]))
  }

  public onDidChangeTreeData(
    listener: (changedItemIds: TreeItemIndex[]) => void
  ): Disposable {
    const id = (Math.random() + 1).toString(36).substring(7)
    this.handlers[id] = listener
    return { dispose: () => delete this.handlers[id] }
  }

  public async onRenameItem(item: TreeItem<any>, name: string): Promise<void> {
    if (this.setItemName) {
      this.data.items[item.index] = this.setItemName(item, name)
    }
  }

  public resetData(items: Record<TreeItemIndex, TreeItem<T>>): void {
    this.data = { items }
    console.log('resetData', this.data) // this looks correct!
  }
}
paulfedory commented 1 year ago

Nevermind, I wasn't re-rendering the tree properly! (needed to change the key after updating the data)

twister124 commented 1 year ago

Hey @paulfedory

I have the same issue. Can you please share the part of the code where u use your CustomDataProvider? And what do you mean needed to change the key after updating the data?

mikebridge commented 7 months ago

Nevermind, I wasn't re-rendering the tree properly! (needed to change the key after updating the data)

@paulfedory what do you mean by updating the key? I have a custom data provider and an UncontrolledTreeEnvironment, but setting a UncontrolledTreeEnvironment key to e.g. Math.Random().toString() doesn't seem to cause it to display my new tree items.