fix(transfer): ensure onEndReached is called when the options change and the list end is visible
#1715
+166
−357
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.




Context / Problem description
We @dhis2/analytics-frontend have a few places where we lazy-load options into
Transfercomponents. This wasn't always working and the problem couldn't really be solved in the app.As can perhaps be seen by the change in PR title and the difference in implementation between commits, it took me a while to get a clear picture of whether this was a bug, of if we needed a new feature which would allow apps to solve the problem. In the end, I settled on the following problem evaluation:
onEndReachedprop is a callback that theTransfershould call when "the end of a list is reached". There is some ambiguity here.IntersectionDetectorsubscription which would fire when there is a change in theisIntersectingvalue and the new value isfalse. Effectively this means the callback only fires under two circumstances:IntersectionDetector(so on mount) and the list end is in viewIntersectionObserver(browser API) would actually notify it's subscribers, but ourIntersectionDetectorcomponent only calls the provided callback when a change is detected and since the value ofisIntersectingwastrueand remainstruethis won't happen. The problem for apps usingonEndReachedfor lazy loading is that now the process gets stuck: a new page actually needs to be fetched but the trigger for doing so is not called.optionsarray, but all of these options are selected. This means none of them will be added to the "source list" and the source list will remain static, and theIntersectionObserveritself would not be of any use here either.So my final conclusion was: this is a bug, the correct behaviour for calling
onEndReachedis that it happens in two cases:Solution
To detect events where options are added we simply monitor the
optionsarray length. And when we detect this, we check if the list end is in view and if so, we call the callback.While this sounds simple enough, it's not so easy to do in React. The
Transferhas actions to the "raw" options, but not the elements that need to be measured. TheOptionsContainerdoes have access to these DOM elements, but here the options have already be filtered which would mean that we'd fail the edge case I mentioned above.I solved this problem by adding a context provider. After writing the above, I realised that I could have possibly also solved this in the
OptionsContaineritself by passing an optionalallOptionsCountprop from theTransfer. I guess that solution would have been a bit simpler, but adding a context does provide a fairly clean solution, and it could also be a way to implement other functionality in and ergonomic way.Notes
Checklist