Describe the bug
Since 2.6.3, UncontrolledTreeEnvironment crashes with an unhandled promise rejection — TypeError: Cannot read properties of undefined (reading 'index') — whenever the data provider resolves undefined for one of the requested ids.
The 2.6.3 refactor of the item-map build (20971e8 + 66d6f1d, closing #441) replaced
items.map(item => ({ [item?.index]: item }))
with
for (const item of items) {
itemMap[item.index] = item;
}
in both the onDidChangeTreeData listener and the onMissingItems batch in UncontrolledTreeEnvironment.tsx — dropping the ?. guard that 2.6.2 had in the onMissingItems path. The library's own StaticTreeDataProvider.getTreeItem returns this.data.items[itemId], i.e. plain undefined for an id not in its record, so the built-in provider is enough to trigger it. Because the throw happens inside an async callback (the setTimeout in onMissingItems), it surfaces as an unhandled rejection and the whole writeItems batch is skipped, so the items that did resolve never render either.
To Reproduce
- Create a
StaticTreeDataProvider over a record where some item referenced in a parent's children has no entry of its own (the standard shape for lazily-loaded trees: children ids arrive before their bodies, then the provider is swapped once the data lands).
- Render it in an
UncontrolledTreeEnvironment and expand the parent.
- On 2.6.2 the missing id is silently skipped; on 2.6.3 the environment throws
Cannot read properties of undefined (reading 'index') and none of the batch's items are written.
Expected behavior
Same as 2.6.2: ids the provider cannot resolve are skipped, and the items that did resolve are still written. E.g.:
for (const item of items) {
if (item != null) itemMap[item.index] = item;
}
in both loops (the onDidChangeTreeData one never had the guard, but before the refactor an undefined item only produced a garbage { undefined: undefined } entry instead of killing the batch).
Screenshots
N/A — stack trace above.
Additional context
- react-complex-tree 2.6.3 (regression from 2.6.2), React 19, Chrome (also reproduced headless in Cypress CI).
- Downstream workaround we ship: subclass
StaticTreeDataProvider with a getTreeItems that filters undefined out, which CompleteTreeDataProvider picks up ahead of the per-id fallback.
Describe the bug
Since 2.6.3,
UncontrolledTreeEnvironmentcrashes with an unhandled promise rejection —TypeError: Cannot read properties of undefined (reading 'index')— whenever the data provider resolvesundefinedfor one of the requested ids.The 2.6.3 refactor of the item-map build (20971e8 + 66d6f1d, closing #441) replaced
with
in both the
onDidChangeTreeDatalistener and theonMissingItemsbatch inUncontrolledTreeEnvironment.tsx— dropping the?.guard that 2.6.2 had in theonMissingItemspath. The library's ownStaticTreeDataProvider.getTreeItemreturnsthis.data.items[itemId], i.e. plainundefinedfor an id not in its record, so the built-in provider is enough to trigger it. Because the throw happens inside an async callback (thesetTimeoutinonMissingItems), it surfaces as an unhandled rejection and the wholewriteItemsbatch is skipped, so the items that did resolve never render either.To Reproduce
StaticTreeDataProviderover a record where some item referenced in a parent'schildrenhas no entry of its own (the standard shape for lazily-loaded trees: children ids arrive before their bodies, then the provider is swapped once the data lands).UncontrolledTreeEnvironmentand expand the parent.Cannot read properties of undefined (reading 'index')and none of the batch's items are written.Expected behavior
Same as 2.6.2: ids the provider cannot resolve are skipped, and the items that did resolve are still written. E.g.:
in both loops (the
onDidChangeTreeDataone never had the guard, but before the refactor an undefined item only produced a garbage{ undefined: undefined }entry instead of killing the batch).Screenshots
N/A — stack trace above.
Additional context
StaticTreeDataProviderwith agetTreeItemsthat filtersundefinedout, whichCompleteTreeDataProviderpicks up ahead of the per-id fallback.