Hi,
I’m working on a Phoenix LiveView project where I have a sticky aside that should persist its open/closed state across page navigations. I pass the initial state (1drawer_open1) in the LiveSocket parameters and then use a hook to sync UI state changes to local storage. This works fine without the sticky option, but when sticky is enabled, the parent mount runs twice (which I think is part of the standard LV lifecycle):
- First mount:
drawer_open = get_connect_params(socket)["drawer_open"]
returnsnil
- Second mount: The correct value is present, but the sticky aside has already rendered using the initial (nil) value from the session.
let liveSocket = new LiveSocket("/live", Socket, {
longPollFallbackMs: 2500,
params: {
_csrf_token: csrfToken,
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
...initialUIState,
},
hooks,
});
The in the parent liveview:
def mount(_params, _session, socket) do
drawer_open = get_connect_params(socket)["drawer_open"]
socket =
socket
|> assign(drawer_open: drawer_open)
{:ok, socket}
end
Which passes it to the sticky liveview:
{live_render(@socket, Aside,
id: "aside",
session: %{
"view" => @live_action,
"drawer_open" => @drawer_open
},
sticky: true
)}
And the sticky LV:
def mount(_params, session, socket) do
drawer_open = session["drawer_open"]
socket =
socket
|> assign(drawer_open: drawer_open)
{:ok, socket}
end
Because the sticky view renders on the first pass, subsequent changes (on the second mount) are ignored. Without sticky, the navigation feels janky, so I really need the sticky behavior along with the correct persisted state.
Question:
How can I ensure that the sticky aside mounts with the correct initial value from get_connect_params(socket)
? Are there recommended approaches to delay rendering or update the sticky component after the correct value is obtained?
Any insights or workarounds would be greatly appreciated!