minop1205 / react-dnd-treeview

A draggable / droppable React-based treeview component. You can use render props to create each node freely.
MIT License
533 stars 71 forks source link

Add search result auto-expansion and virtualization support for large trees #230

Open Duck-98 opened 5 days ago

Duck-98 commented 5 days ago

Is your feature request related to a problem? Please describe. When searching and filtering tree data, nodes that match the search criteria are not visible if their parent nodes are collapsed. This creates a poor user experience as users cannot immediately see all search results and must manually expand multiple parent nodes to find the matching items.

For example, if I search for "item-3-2" which is nested under "folder-1/folder-2/folder-3", I cannot see the result unless all parent folders are already expanded.

Describe the solution you'd like I would like to implement two key features:

  1. Enhanced Search Functionality:

    • Automatically expand parent nodes when their children match search criteria
    • Highlight matched nodes for better visibility
    • Show breadcrumb path for deeply nested search results
  2. Virtualization Support:

    • Implement virtual scrolling to handle large data sets efficiently
    • Only render visible nodes to improve performance
    • Maintain smooth scrolling even with expanded search results

Describe alternatives you've considered

  1. Implementing a separate search results panel that shows matched items in a flat list
    • This would work but breaks the hierarchical context of the tree
  2. Only showing matched nodes and their direct parents
    • This would be simpler but might lose important context from the tree structure

Additional context This enhancement would significantly improve the usability of the tree component, especially for large data sets where users need to quickly find specific items in a deep hierarchy. The current implementation requires too many manual interactions to view search results.

For the virtualization feature, I plan to utilize the react-window library, which is well-maintained and provides excellent performance for handling large lists and grid layouts. This library would help us implement efficient virtual scrolling while maintaining smooth performance even with expanded trees containing many nodes.

I would greatly appreciate your feedback on this feature request. If you think this would be a valuable addition to the library, I would be happy to contribute to its implementation. Please let me know if you would like me to proceed with this enhancement and if you have any specific guidelines or considerations I should keep in mind while implementing these features.

minop1205 commented 4 days ago

@Duck-98 Thank you for your comment!

For the search functionality, we prefer to provide a hook or helper rather than extending the functionality of the component. We would like to leave the specific implementation to the users of this library, as there are many possible use cases for how to display the search results. For example

const [filteredTree, openIds] = useTreeSearch(searchText);.

This takes a search string as an argument and returns the filtered tree and the IDs of the nodes that should be opened.

Regarding virtualization of the tree, I think it is difficult to virtualize the tree because all the nodes in the tree are not flat but nested, but I don't have a good idea for this. I would like to know if you have any solutions. Tree virtualization is a feature that has been requested since the beginning of this library, so if it can be implemented without sacrificing functionality, it would be welcome.

Duck-98 commented 2 days ago

@minop1205 Thank you for your thoughtful feedback on the tree virtualization and search functionality. I'd like to propose a detailed implementation approach that addresses both the performance concerns and maintains the library's flexibility:

Regarding virtualization

  1. While I initially attempted to implement virtualization while preserving the nested tree structure, I found that flattening the tree structure provides a more efficient solution. However, I want to emphasize that:

    • The flattening transformation will only occur when virtualization is enabled
    • When virtualization is not needed, the tree will maintain its original nested structure
    • This approach ensures we don't impose unnecessary performance overhead on simpler use cases
  2. For the technical implementation, I'm proposing to use @tanstack/react-virtual instead of react-window. The reasons for this choice are

    • Significantly smaller bundle size
    • Rich set of built-in hooks that provide more flexibility
    • Better maintenance and community support
    • More modern API design
  3. The implementation will preserve all existing functionality, including

    • Drag and drop capabilities
    • Tree manipulation (expand/collapse)
    • All current event handlers and callbacks
    • Existing styling and customization options
  4. Performance optimizations will include:

    • Rendering only visible nodes in the viewport
    • Efficient node expanding/collapsing
    • Smooth scrolling experience
    • Minimal re-renders

Regarding the search functionality:

  1. As you suggested, I'll implement this as a separate hook (e.g., useTreeSearch) that:
    • Provides default search logic out of the box
    • Allows for custom search implementation through options
    • Returns both filtered results and expanded node IDs

Example search hook usage would look like:

const { filteredTree, expandedIds } = useTreeSearch(tree, searchQuery, {
 searchFn: (node, query) => // custom implementation,
// ...etc (yet)
});

Would this approach align with the library's goals? I can proceed with a proof-of-concept implementation if you think this direction makes sense.

I'm particularly interested in your thoughts on:

  1. The choice of @tanstack/react-virtual over react-window
  2. The conditional flattening approach based on virtualization being enabled
  3. Any specific edge cases or scenarios you'd like me to consider in the implementation