-
Notifications
You must be signed in to change notification settings - Fork 558
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RFC: Adding transitions to Suspense #154
Conversation
Cross-linking #128 , which seems similar in intent |
How do we follow progress on this issue? |
Hi! But there is one thing that bothers me: you actively use There is another thing i'd like to discuss: whether unmount transition should be interruptible? |
This would be amazing. |
In the spirit of #182, I'll provide some cursory comments about this proposal. It's a bit challenging to read because the proposal mixes the proposed API with the "demo implementation", and it's a bit hard to tell where the parts you're proposing end, and the parts that were necessary to get the sandboxes running begin. I'm going to take a guess that the core of the proposal is the With that assumption, "Proposal 1" looks unclear and incomplete. It doesn't seem to solve on the API level what you set out to solve, because, indeed, it's unclear how a parent component would receive a child Suspense status. (What is the API it would use? A proposal should specify a hypothetical one.) You call that out in the drawbacks. I think we can ignore this proposal because it doesn't propose a concrete API. "Proposal 2" is clearer. Essentially, you're proposing this: <Suspense
fallback={<Fallback />}
Wrapper={SomeWrapper} // <--- this is the proposal
>
<Child />
</Suspense> There are some nitpicks, like the fact that "Proposal 3" <Suspense>
{isWaiting => ( // <---- this is the proposal
<Wrapper isWaiting={isWaiting}>
{isWaiting ? <Fallback /> : <Child />}
</Wrapper>
)}
</Suspense> This render prop API, in my opinion, is the substance of this RFC. (Btw, fun fact: if I recall correctly, this is also the API we started with. That was the initial Suspense API that we removed later.) Currently, even if we switched the API to be like this, I don't think it would be sufficient for third-party animation solutions to work. This is because React handles switching between the fallback tree and the content tree differently from a regular component update. Specifically, switching between them (intentionally!) doesn't destroy the DOM. E.g. when you switch from content to fallback due to re-suspending, we hide (not remove!) the content, insert the fallback, and later show the content. This is different from unmounting in that we preserve the component state and the DOM state (e.g. a video player or a text input). Even if we exposed a render prop-like API, a Framer Motion or React Transition Group wrapper wouldn't be able to do the same thing. In addition, we wouldn't be able to distinguish between what to hide and what to remove because the information about them being separate trees is lost. This type of API (just as Proposal 2) is "too powerful" and loses the distinction between the content tree and the fallback tree, which are conceptually two separate trees with different behaviors. In general, the idea that there needs to be an API controlling enter/exit for Suspense makes sense though. But it's also very limiting to implement this just for Suspense. Enter/exit animations are in general a very compelling feature, and third-party solutions are limited in what they can do. E.g. there is a common limitation in that the node being removed has to be a direct descendant of the wrapper component like As for how a generic solution would look like, we're not sure yet. But it probably follows a similar shape to what I outlined above, except it wouldn't be tied to Suspense. Something we've been discussing is a component like this: <Presence>
{status => // Enum: "visible" | "enter" | "exit"
/* render anything */
}
</Presence> Crucially, this wrapper is NOT meant to wrap the deleted/inserted children, but the other way around. It's about specifying "what should be rendered as this subtree is being added/removed due to a change from a parent". E.g. in a list, an This approach isn't specific to Suspense, but it would work for Suspense too, and would let us preserve the distinction between content/fallback trees, and the special behavior when switching them. <Suspense fallback={<Fallback />}>
<Child />
</Suspense>
function Fallback() {
return (
<Presence>
{status => <Spinner opacity={status === 'exit' ? 0 : 1} />}
</Presence>
)
}
function Child() {
// ... could also use Presence ...
} This would let you do something like a crossfade between content and fallback. We'd also want to provide built-in support for layout animation which would let you automatically animate their parent box. But animations are a much broader topic in general, and it will be a big effort to design the API and implement it. I'm happy to keep this RFC open for discussion but I hope this context explains how we're thinking about these features and how they fit together in the long term. |
Thank you Dan for all the feedback. I will close this PR as it seems apparent that this issue will be better addressed in future React api releases that are agnostic of Suspense. |
This RFC originated from this issue and proposes enhancing the suspense api such that it can enable transition effects for the fallback and children components by communicating to these components when suspense is "waiting". This will allow these components to render transitions when they mount and unmount by using libraries such as Framer Motion, React Spring, React Transition Group, and more.
View formatted RFC