|
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