Skip to content

Commit 44883e4

Browse files
committed
docs: samples on adding and removing items (#145)
1 parent c96c39d commit 44883e4

File tree

4 files changed

+48
-5
lines changed

4 files changed

+48
-5
lines changed

packages/docs/docs/4-recipes/0-external-state-updates.mdx

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ title: "Handling external state updates"
44
category: recipe
55
---
66

7+
import { DemoBox } from "../../src/components/demo/demo-box";
8+
79
Generally, Headless Tree loads the tree structure once when it is loaded, and loads subsequent substructures
810
whenever parts of the visual tree change, e.g. because a folder is expanded that was collapsed before.
911
Headless Tree provides ways to mutate the tree via drag events or renaming, and makes sure that it reloads
@@ -44,8 +46,18 @@ const addNode = () => {
4446
items["item3"] = { name: "Item 3", children: [] };
4547
tree.rebuildTree();
4648
};
49+
50+
const removeNode = () => {
51+
delete items["item2"];
52+
items["item1"].children = items["item1"].children.filter(id => id !== "item2");
53+
tree.rebuildTree();
54+
};
4755
```
4856

57+
The following sample shows how to add and delete items from a synchronous tree, as well mutating their data by renaming them.
58+
59+
<DemoBox tags={["guide/externaldata"]} initialStory={"react-guides-external-data-management-sync-data--sync-data"} />
60+
4961
## Asynchronous Trees
5062

5163
For asynchronous trees, the general gist of how trees are updated is the same, however the `asyncDataLoaderFeature`
@@ -62,4 +74,35 @@ item.invalidateChildrenIds();
6274
```
6375

6476
You will not have to additionally call `tree.rebuildTree()`, as this is done automatically by the async
65-
data loader feature once it has refetched the data.
77+
data loader feature once it has refetched the data.
78+
79+
Instead of invalidating and waiting for a refetch, you can also directly update the cached data of an item
80+
or its cached children ids, if you already have the new data available:
81+
82+
```ts
83+
const item = tree.getItemInstance("item1");
84+
item.updateCachedData({ ...item.getItemData(), name: "New name" });
85+
item.updateCachedChildrenIds(["child1", "child2"]);
86+
```
87+
88+
In the demo below, you can see the same samples for adding and deleting data as above, but with
89+
an async data loader instead. In this sample, the cache is updated with `item.updateCachedChildrenIds()`
90+
and `item.updateCachedData()`. Note that you do need to call `tree.rebuildTree()` after mutating
91+
the data this way.
92+
93+
<DemoBox tags={["guide/externaldata"]} initialStory={"react-guides-external-data-management-async-data--async-data"} />
94+
95+
## Managing tree data in a React state
96+
97+
Most samples in the documentation use a data loader implementation that lives outside of React, since in most
98+
cases the data loader will directly interface with your backend or other external data source to provide
99+
tree data to Headless Tree.
100+
101+
The sample below demonstrates how to manage the tree data in a React state. The most relevant gotcha is that calling
102+
`rebuildTree()` may behave unexpectedly in cases where data is stored in a React state. If you mutate your tree data
103+
by updating the React state, the `useState` getter will only reflect the new state during the next rerender.
104+
Calling `rebuildTree()` immediately after you made your changes, will result in the rebuild logic running on the old
105+
data from before the rerender. To combat this, you can use `tree.scheduleRebuildTree()` instead, trigger a rebuild
106+
the next time `tree.getItems()` is called, which will be after the next rerender.
107+
108+
<DemoBox tags={["guide/externaldata"]} initialStory={"react-guides-external-data-management-data-in-react-state--data-in-react-state"} />

packages/sb-react/src/guides/external-data-management/async-data.stories.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import { DemoItem, createDemoData } from "../../utils/data";
1818

1919
const meta = {
2020
title: "React/Guides/External Data Management/Async Data",
21-
tags: ["guide", "external data"],
21+
tags: ["guide", "guide/externaldata"],
2222
} satisfies Meta;
2323

2424
export default meta;
@@ -55,7 +55,7 @@ export const AsyncData = () => {
5555
}),
5656
onRename: (item, value) => {
5757
data[item.getId()].name = value;
58-
item.updateCachedData({ ...item.getItemData(), name: value }); // TODO mention in rename docs
58+
item.updateCachedData({ ...item.getItemData(), name: value });
5959
},
6060
indent: 20,
6161
dataLoader: asyncDataLoader,

packages/sb-react/src/guides/external-data-management/data-in-react-state.stories.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import { DemoItem, createDemoData } from "../../utils/data";
1818

1919
const meta = {
2020
title: "React/Guides/External Data Management/Data In React State",
21-
tags: ["guide", "external data"],
21+
tags: ["guide", "guide/externaldata"],
2222
} satisfies Meta;
2323

2424
export default meta;

packages/sb-react/src/guides/external-data-management/sync-data.stories.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import { DemoItem, createDemoData } from "../../utils/data";
1818

1919
const meta = {
2020
title: "React/Guides/External Data Management/Sync Data",
21-
tags: ["guide", "external data"],
21+
tags: ["guide", "guide/externaldata"],
2222
} satisfies Meta;
2323

2424
export default meta;

0 commit comments

Comments
 (0)