|
1 | 1 | ---
|
2 |
| -sidebar_position: 2 |
| 2 | +sidebar_position: 2.5 |
3 | 3 | ---
|
4 | 4 |
|
5 |
| -# Data Provider |
| 5 | +# Custom Tree Data Provider |
6 | 6 |
|
7 |
| -When using an uncontrolled environment, you need to provide your data by supplying a data provider. The |
8 |
| -easiest way to get started is using the [Static Tree Data Provider](/docs/api/classes/StaticTreeDataProvider). |
9 |
| -It allows you to provide your data as record which maps item ids to tree items, and gives you the possibility |
10 |
| -to react to changes in the tree structure, as well as inject your own changes through change events. |
11 |
| - |
12 |
| -# Static Tree Data Provider |
13 |
| - |
14 |
| -The following example gives a good example of what is possible with static tree data providers. We will look |
15 |
| -into the details of the data provider below. |
16 |
| - |
17 |
| -```jsx live |
18 |
| -function App() { |
19 |
| - const items = useMemo(() => ({ ...shortTree.items }), []); |
20 |
| - const dataProvider = useMemo( |
21 |
| - () => |
22 |
| - new StaticTreeDataProvider(items, (item, data) => ({ |
23 |
| - ...item, |
24 |
| - data, |
25 |
| - })), |
26 |
| - [items] |
27 |
| - ); |
28 |
| - |
29 |
| - const injectItem = () => { |
30 |
| - const rand = `${Math.random()}`; |
31 |
| - items[rand] = { data: 'New Item', index: rand }; |
32 |
| - items.root.children.push(rand); |
33 |
| - dataProvider.onDidChangeTreeDataEmitter.emit(['root']); |
34 |
| - }; |
35 |
| - |
36 |
| - const removeItem = () => { |
37 |
| - if (items.root.children.length === 0) return; |
38 |
| - items.root.children.pop(); |
39 |
| - dataProvider.onDidChangeTreeDataEmitter.emit(['root']); |
40 |
| - }; |
41 |
| - |
42 |
| - return ( |
43 |
| - <UncontrolledTreeEnvironment |
44 |
| - canDragAndDrop |
45 |
| - canDropOnFolder |
46 |
| - canReorderItems |
47 |
| - dataProvider={dataProvider} |
48 |
| - getItemTitle={item => item.data} |
49 |
| - viewState={{ |
50 |
| - 'tree-1': { |
51 |
| - expandedItems: [], |
52 |
| - }, |
53 |
| - }} |
54 |
| - > |
55 |
| - <button type="button" onClick={injectItem}> |
56 |
| - Inject item |
57 |
| - </button> |
58 |
| - <button type="button" onClick={removeItem}> |
59 |
| - Remove item |
60 |
| - </button> |
61 |
| - <Tree treeId="tree-1" rootItem="root" treeLabel="Tree Example" /> |
62 |
| - </UncontrolledTreeEnvironment> |
63 |
| - ); |
64 |
| -} |
65 |
| -``` |
66 |
| - |
67 |
| -## Creating the data provider with data |
68 |
| - |
69 |
| -First, create the data provider. You want to make sure it isn't recreated on re-renders, so memoize |
70 |
| -it in the component in which it is defined. |
71 |
| - |
72 |
| -```tsx |
73 |
| -const dataProvider = useMemo( |
74 |
| - () => |
75 |
| - new StaticTreeDataProvider(items, (item, data) => ({ |
76 |
| - ...item, |
77 |
| - data, |
78 |
| - })), |
79 |
| - [items] |
80 |
| -); |
81 |
| -``` |
82 |
| - |
83 |
| -The items is a record mapping item ids to tree items, for example: |
84 |
| - |
85 |
| -```typescript |
86 |
| -const items = [ |
87 |
| - { |
88 |
| - index: "item-id", |
89 |
| - data: { arbitraryData: 123, name: "Hello" }, |
90 |
| - children: ["item-id-1", "item-id-2"], |
91 |
| - isFolder: true |
92 |
| - } |
93 |
| -] |
94 |
| -``` |
95 |
| - |
96 |
| -Note that, whatever you provide to the `getItemTitle` prop is used to infer the item display name. |
97 |
| - |
98 |
| -```ts jsx |
99 |
| -<UncontrolledTreeEnvironment |
100 |
| - getItemTitle={item => item.data.name} |
101 |
| -/> |
102 |
| -``` |
103 |
| - |
104 |
| -## Apply changes from outside |
105 |
| - |
106 |
| -You can apply changes to the underlying data source. Just make sure to let RCT know about that by |
107 |
| -emitting a change event on the affected items. Note that, if you add or remove items, the affected item |
108 |
| -is the parent item, not the added or removed items. |
109 |
| - |
110 |
| -```ts |
111 |
| -const injectItem = () => { |
112 |
| - const rand = `${Math.random()}`; |
113 |
| - items[rand] = { data: 'New Item', index: rand }; |
114 |
| - items.root.children.push(rand); |
115 |
| - dataProvider.onDidChangeTreeDataEmitter.emit(['root']); |
116 |
| -}; |
117 |
| - |
118 |
| -const removeItem = () => { |
119 |
| - if (items.root.children.length === 0) return; |
120 |
| - items.root.children.pop(); |
121 |
| - dataProvider.onDidChangeTreeDataEmitter.emit(['root']); |
122 |
| -}; |
123 |
| -``` |
124 |
| - |
125 |
| -## Reacting to Drag Events |
126 |
| - |
127 |
| -Drag changes are always immediately applied to the visualization, so make sure to implement the `canDropAt` |
128 |
| -prop to customize if that should not work in all cases. The static tree data emits tree change events similar |
129 |
| -to the ones you would emit when applying changes from outside, so you can react to them in the same way. |
130 |
| - |
131 |
| -```typescript |
132 |
| -dataProvider.onDidChangeTreeData(changedItemIds => { |
133 |
| - console.log(changedItemIds); |
134 |
| -}); |
135 |
| -``` |
136 |
| - |
137 |
| -## Reacting to Rename Events |
138 |
| - |
139 |
| -The second (optional) parameter of the static tree data provider lets you react to rename events. Note that |
140 |
| -you can customize whether renaming is possible in the first place through the `canRename` prop. |
141 |
| - |
142 |
| -```typescript |
143 |
| -const dataProvider = new StaticTreeDataProvider(items, (item, newName) => { |
144 |
| - // Return the patched item with new item name here |
145 |
| - return { |
146 |
| - ...item, |
147 |
| - data: { ...item.data, name: newName }, |
148 |
| - }; |
149 |
| -}); |
150 |
| -` |
151 |
| -``` |
152 |
| - |
153 |
| -## Custom Data Provider |
154 | 7 |
|
155 | 8 | In more complex scenarios, it's probably easiest to implement your own data provider.
|
156 | 9 | This provider must implement the [TreeDataProvider interface](/docs/api/interfaces/TreeDataProvider), i.e.
|
|
0 commit comments