You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I have been really enjoying my explorations into building better 'compound components' using the experimental react-call-return. This issue is intended to start a discussion of some of the shortcomings of the current API that I ran into.
Experiments in which the return is used as a leaf node that yields some data are very successful. Since #11955 was solved I have not run into further issues with the stability of this feature.
However, for 'compound component' usage, to implement features such as layout, my return often yields an element or render prop. In these cases, these elements are rendered with the call as the parent, and any context created in the first pass (between the call and return) is lost.
A reproduction case can be found here: https://codesandbox.io/s/0p4lvy72pl, as an end-user of these components (unaware that they use call-return internally), I would expect to see 'Greetings 1' instead of 'Default 1'.
I don't consider this a bug, but rather a side-effect of how I'm using the API. However, I believe the use-case above is a valid one and providing an API that supports this would be beneficial to library authors. Below I'll share some thoughts on such an API for discussion.
Initially, the API was called coroutine and yield, which suggested a subtree would yield and later resume. Presumably, this is why the API was renamed. My suggestion would be to implement the coroutine-yield functionality, which continues rendering the 'continuation' as children of the yield fiber. Of course I am not aware of all the choices that led to the current API, so input here is welcomed.
createCoroutine(children, handler, props) would function very similarly to the current createCall, but the handler does not return the children to render. Instead, it returns some aggregated value. This value is passed to the second argument of createYield(value, continuation, props), together with that yield element's props and index within the coroutine. The element returned from the continuation is reconciled with the yield fiber's children, preserving its position in the tree and thus also any context that was accumulated between the coroutine and yield.
Note that the new API would be a strict superset of the current implementation, I imagine the call-return could be written with coroutine and yield as follows:
I've dived into the reconciler implementation for call and return, and implementing an API like the above seems feasible to me. I'd definitely be willing to give it a shot once the approach is clear. However, I am not aware of all the decisions that led up to the current implementation, and the exact impact on performance (increased tree traversals) etc...
EDIT: I've prototyped this API on CodeSandbox here: https://codesandbox.io/s/480nx1qw97, it causes multiple renders using setState and forceUpdate, and uses some nasty traversals of _reactInternalFiber, it is highly unstable, but it illustrates the idea outlined above.
The text was updated successfully, but these errors were encountered:
Since there hasn't been any discussion, I am unsure how to move forward with this. I am not confident moving forward with creating an RFC, since the approach is still unclear.
I realize that the initial post is quite long and perhaps slightly vague, any input or clarifying questions are welcomed.
Thanks for the heads-up, if there is a way for me to join the discussion, I would be happy to. I believe that an API in this area could really strengthen some of the abstractions we're trying to make. Layout is only one of those cases!
I have been really enjoying my explorations into building better 'compound components' using the experimental
react-call-return
. This issue is intended to start a discussion of some of the shortcomings of the current API that I ran into.Experiments in which the
return
is used as a leaf node that yields some data are very successful. Since #11955 was solved I have not run into further issues with the stability of this feature.However, for 'compound component' usage, to implement features such as layout, my
return
often yields an element or render prop. In these cases, these elements are rendered with thecall
as the parent, and any context created in the first pass (between thecall
andreturn
) is lost.A reproduction case can be found here: https://codesandbox.io/s/0p4lvy72pl, as an end-user of these components (unaware that they use call-return internally), I would expect to see 'Greetings 1' instead of 'Default 1'.
I don't consider this a bug, but rather a side-effect of how I'm using the API. However, I believe the use-case above is a valid one and providing an API that supports this would be beneficial to library authors. Below I'll share some thoughts on such an API for discussion.
Initially, the API was called coroutine and yield, which suggested a subtree would yield and later resume. Presumably, this is why the API was renamed. My suggestion would be to implement the coroutine-yield functionality, which continues rendering the 'continuation' as children of the yield fiber. Of course I am not aware of all the choices that led to the current API, so input here is welcomed.
createCoroutine(children, handler, props)
would function very similarly to the currentcreateCall
, but the handler does not return the children to render. Instead, it returns some aggregated value. This value is passed to the second argument ofcreateYield(value, continuation, props)
, together with that yield element's props and index within the coroutine. The element returned from the continuation is reconciled with the yield fiber's children, preserving its position in the tree and thus also any context that was accumulated between the coroutine and yield.Note that the new API would be a strict superset of the current implementation, I imagine the call-return could be written with coroutine and yield as follows:
I've dived into the reconciler implementation for call and return, and implementing an API like the above seems feasible to me. I'd definitely be willing to give it a shot once the approach is clear. However, I am not aware of all the decisions that led up to the current implementation, and the exact impact on performance (increased tree traversals) etc...
CC'ing @sebmarkbage and @gaearon
EDIT: I've prototyped this API on CodeSandbox here: https://codesandbox.io/s/480nx1qw97, it causes multiple renders using
setState
andforceUpdate
, and uses some nasty traversals of_reactInternalFiber
, it is highly unstable, but it illustrates the idea outlined above.The text was updated successfully, but these errors were encountered: