react-d3-tree
react-d3-tree copied to clipboard
Support for dynamic `data` scenarios
Thank you for taking the time to report an issue with react-d3-tree!
Feel free to delete any questions that do not apply.
Are you reporting a bug, or opening a feature request?
Bug
What is the actual behavior/output?
When updating the data dynamically with a state, the tree data doesn't actually update. The data I set at creation is the only data that it displays, regardless if I update it in the state or not.
What is the behavior/output you expect?
I expect the internal data of the tree to update.
Can you consistently reproduce the issue/create a reproduction case (e.g. on https://codesandbox.io)?
I would need access to our system, so no, but I am willing to share whatever you need to see.
What version of react-d3-tree are you using?
2.0.0
Update: When I wrap it in a container, it clearly shows that it is indeed updating, but it is also rerendering. Is there a way to stop the rerender?
If anyone else is facing this issue, I found a workaround by doing the following:
- Wrapping the <Tree/> object in a functional react element. I just used:
const TreeWrapper = () => { return ( <Tree/> // Add your props linked to the state in here ) }
- I also left the initial depth at default, so the entire tree renders. This results in the tree rerendering the updated data that is fetched from an API, which gives the illusion that it just fetched the new data.
- Then I also saved the zoom and translations, so when the tree rerenders, it re-renders at the last position, rather than at a default position.
Hi @LunarAI, thanks for making me aware of this issue in v2.
I've created a small repro attempt with a (simplified) data fetch here (codesandbox.io). By default the tree seems to append data as expected, so it's not clear to me what exactly you're encountering in your case.
Could you fork the sandbox and configure it in a way that reproduces the issue? If you can't reproduce it there, please post an excerpt of your Tree component and which TreeProps/configuration you're using.
I'm aware that this is generally a tricky use case (#201; saw your additional comment there too), so I'm keen to do some bug squashing and adding explicit support for incremental data fetching.
Hi @bkrem, I am so sorry for not getting back to you yet. I will try to replicate it and submit the link here. It will probably be in early February.
No need to apologise 😄 Thanks again for bringing my attention (back) to this, since it's a use case that should get first-class support instead of requiring workarounds due to re-render quirks.
I think I realised what you were encountering after re-reading your explanations and playing around with the codesandbox above some more:
Without setting any initialDepth
this approach works (as you mentioned in your workaround, thank you for that too 👌 ).
But there's definitely unintended behaviour when using initialDepth
together with this incremental fetching approach due to re-rendering, i.e. the tree becomes "frozen".
I'm looking into a fix for the issue at the moment 🤞
Hi @bkrem. We have a similar issue where we are filtering a large amount of data, so need to add the data incrementally. I have replicated your codesandbox and have it working, but as you mention we need to set the initialDepth because the tree freezes when removed. Do you have any updates on if you are any closer to fixing the issue? I realise your last comment was just 5 weeks ago. Thanks.
Hi @stevepetebruce,
February was a super busy month for me both in- and outside of work, but I had some time this weekend to look more deeply into this topic and make some progress.
I want to clarify that this is really a whole new feature set for the library (explained below), rather than a bug, since there's currently no explicit support for this advanced use case.
TL;DR: react-d3-tree
does not currently differentiate between the concepts of two distinct data
sets vs one augmented/modified data
set. I'm currently figuring out how to allow for this differentiation in a meaningful way without adding boatloads of complexity.
The key issue is the following:
If
data
changes, how doesTree
know whether the new value is an entirely different dataset (A -> B) or is a mutation of the previous dataset (A -> A*)?
This differentiation can be achieved by adding a new dataKey: string | number
prop:
-
data
changed, butdataKey
is unchanged? It'sA -> A*
-
data
anddataKey
both changed? It'sA -> B
This approach works, but I'm still working on making the tree's behaviour align with common sense for the A -> A*
scenario:
- Previously,
Tree
could forget about all node configurations and reconfigure based oninitialDepth
(or simply render to full depth) wheneverdata
changed. - The
A -> A*
scenario introduces additional statefulness, as existing nodes should preserve their collapsed/expanded state betweendata
changes.
Any solution for this? I am facing a similar challenge, re-rendering the entire tree when tree size gets too big doesn't look like a good option. Any suggestion on how to handle updates in a large tree? Thanks.
I saw the recent merge of https://github.com/bkrem/react-d3-tree/pull/417/files by @bkrem last month. Thanks. It looks like what I want but I've had no luck. Is there a test or example of using dataKey?
If I specify a dataKey (an id from my root node) on initial render then nothing renders. If I useState to set a datakey after my initial render of data that's fine but changes to data still re-render the tree (expanding all collapsed nodes). Seems like maybe the dataKey test in getDerivedStateFromProps should/could look to see it there is no prevState data and go ahead and render if not. Might save some hassle.
I was adding the children to my data manually so then I thought maybe I could/had to use the addChildren function. I called that from within my renderCustomNodeElement function but it doesn't add any children. I can see the children being pushed onto targetNodeDatum in handleAddChildrenToNode but they don't render and aren't on the nodeDatum in subsequent calls to renderCustomNodeElement. Probably a mistake in how I'm implementing this.
I tried modifying the codesandbox example above but couldn't get a version above 3.5.1 there.