import { DemoBox } from "../../src/components/demo/demo-box";

Generally, Headless Tree loads the tree structure once when it is loaded, and loads subsequent substructures
whenever parts of the visual tree change, e.g. because a folder is expanded that was collapsed before.
Headless Tree provides ways to mutate the tree via drag events or renaming, and makes sure that it reloads
those parts that have changed automatically if one of
`removeItemsFromParents()`, `insertItemsAtTarget()` or `createOnDropHandler()`
was used (see [the Guide on mutating your data after the Drop](https://headless-tree.lukasbach.com/llm/dnd/overview.md) for details).

However, in many cases you will want to update the tree structure of your data based on external events. In this
case you need to inform Headless Tree, that the tree structure has changed, so that it can update the rendering
of the affected parts.

## Synchronous Trees

For Trees using the [`syncDataLoader`](https://headless-tree.lukasbach.com/llm/features/sync-dataloader.md) feature, the gist of data loading is as follows:
Headless Tree maintains an internal representation of a flattened view of the tree, that is generated based on
the `dataLoader` information that is available when the tree renders. This information is regenerated whenever
`tree.rebuildTree()` is called, which is done automatically when items are expanded/collapsed
or drag events are fulfilled with one of the aforementioned drag-related update-methods. The react component then
needs to re-render for the visual changes to come into affect, which is also done automatically in those cases since
`tree.rebuildTree()` triggers an update to the tree state which will also re-render the component.

If you mutate the data, you will need to call `tree.rebuildTree()` manually, so that Headless Tree can update the internal
representation of the tree. Make sure that this call happens *after* the data loader has access to the mutated data.

```ts
const items = {
  item1: { name: "Item 1", children: ["item2"] },
  item2: { name: "Item 2", children: [] },
}

const dataLoader = {
  getItem: (id: string) => items[id],
  getChildren: (id: string) => items[id].children,
};

const addNode = () => {
  items["item1"].children.push("item3");
  items["item3"] = { name: "Item 3", children: [] };
  tree.rebuildTree();
};

const removeNode = () => {
  delete items["item2"];
  items["item1"].children = items["item1"].children.filter(id => id !== "item2");
  tree.rebuildTree();
};
```

The following sample shows how to add and delete items from a synchronous tree, as well mutating their data by renaming them.



## Asynchronous Trees

For asynchronous trees, the general gist of how trees are updated is the same, however the `asyncDataLoaderFeature`
provides the additional functionality of caching item information of tree data, which means that just triggering
`tree.rebuildTree()` will do nothing as it will just keep using the stale information before the update.

When using the `asyncDataLoaderFeature`, additional methods are available on item instances to trigger them
to invalidate their data:

```ts
const item = tree.getItemInstance("item1");
item.invalidateItemData();
item.invalidateChildrenIds();
```

You will not have to additionally call `tree.rebuildTree()`, as this is done automatically by the async
data loader feature once it has refetched the data.

Instead of invalidating and waiting for a refetch, you can also directly update the cached data of an item
or its cached children ids, if you already have the new data available:

```ts
const item = tree.getItemInstance("item1");
item.updateCachedData({ ...item.getItemData(), name: "New name" });
item.updateCachedChildrenIds(["child1", "child2"]);
```

In the demo below, you can see the same samples for adding and deleting data as above, but with 
an async data loader instead. In this sample, the cache is updated with `item.updateCachedChildrenIds()`
and `item.updateCachedData()`. Note that you do need to call `tree.rebuildTree()` after mutating
the data this way.



## Managing tree data in a React state

Most samples in the documentation use a data loader implementation that lives outside of React, since in most
cases the data loader will directly interface with your backend or other external data source to provide
tree data to Headless Tree.

The sample below demonstrates how to manage the tree data in a React state. The most relevant gotcha is that calling
`rebuildTree()` may behave unexpectedly in cases where data is stored in a React state. If you mutate your tree data
by updating the React state, the `useState` getter will only reflect the new state during the next rerender. 
Calling `rebuildTree()` immediately after you made your changes, will result in the rebuild logic running on the old
data from before the rerender. To combat this, you can use `tree.scheduleRebuildTree()` instead, trigger a rebuild
the next time `tree.getItems()` is called, which will be after the next rerender.

