Make shared state between Islands safe and enhance its use with View Transitions #756
Replies: 4 comments 1 reply
-
I just realized, this problem doesn't happen only with View Transitions. It can happen at any point during the hydration. I just updated my proposal accordingly. |
Beta Was this translation helpful? Give feedback.
-
An alternative approach is to extend // client-myrender.js
export default async (load, opts, el) => {
const trigger = await load()
await trigger({ render: true })
} // In astro
<MyComponent client:myrender /> Since the client directive is a |
Beta Was this translation helpful? Give feedback.
-
Was pointed in the direction of this proposal after submitting my own duplicate issue of this OP's , withastro/astro#9893 Will keep posted on this and am eager to see how it progresses. |
Beta Was this translation helpful? Give feedback.
-
Thanks for the details. Is this issue primarily about how certain frameworks handle hydration/rendering? Render retains state and hydration does not? If that's the case, maybe we can just always use render when "rerendering" a component? I am a little confused though, since we added support for rerunning components on navigation with new props, and in testing the state was retaining there. |
Beta Was this translation helpful? Give feedback.
-
Summary
This proposal aims to enable developers to safely share state across pages and components, as well as enhancing the transition between static components and those that require updates during View Transition navigation. The discussion about this started here: withastro/astro#8781
Full demo of the problem: https://stackblitz.com/edit/github-bxb9uz-hyncuf?file=src%2Fpages%2Findex.astro
Background & Motivation
Shared state brings a lot of convenience and power for Astro users, but as it is right now, it is dangerous to shoot oneself in the foot (E.g. Hydration mismatches) or make bad experiences (E.g. Saving the state of a full-page component with
client:only
causes scroll and screen flash issues when you return).Firstly, the shared state is not safe. If the client modifies the shared state, any subsequent hydration may encounter mismatches. This occurs because the client's suggested DOM structure might differ from what the server initially sent. Most UI Frameworks do not anticipate mismatches and will emit errors when they happen. From my tests Svelte and Lit seem to be the only frameworks that address this mismatch.
Currently, the approach to solve this problem is limited:
transition:persist
.client:only
, which may lead to challenges reminiscent of "flash of white while using dark theme" issue and FOUC problem after View Transition and on first load.useEffect
to replicate what happens in shared state to reflect on its scoped state. Seems to be the best solution for now, but also flash and layout shift may occurr after View Transition and require extra code.Note: The shared state issue doesn't happen only with View Transition, mismatches can happen at any point during the hydration. It just happens to occur more commonly when used with View Transition.
Goals
Design
I provided a detailed comment on the solution. In short, using the
render
function instead of thehydrate
function on load and during the view transition.A new directive can be introduced:
client:swap
, to mark a component that relies on a shared state to be rendered and swapped instead of hydrating. This would ensure a partially hydrated page won't cause any mismatches.. This directive also instructs the component to render the component separately and seamlessly swap during navigation view transition swap stage.In code:
Edge case
There is also the possibility to allow
swap
only after the component visible or the browser is idle, but I don't think is a good practice,client:swap
implies the component already have a high priority. The component always needs to be rendered during view transitions to prevent flashes.Beta Was this translation helpful? Give feedback.
All reactions