[Session] Use flag on state for persistence #3793
Merged
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.
See individual commits.
isInitialLoad
andisSwitchingAccounts
out of the mainstate
object, similar to how they're taken out in [Session] V2 (V2) #3728.state
object shape.Persistence change
Whenever we update
accounts
orcurrentAccount
, we need to persist that change to the local storage. There is only one exception to that — we don't want to do that if the update is coming from another tab (which means it was already persisted — and we want to avoid two tabs entering a cycle of persisting and notifying each other).Well, and we also don't want to persist the initial state.
So how do we do this?
On
main
, persistence is achieved with an explicit call like this:which by itself sets
isDirty.current = true
, and then an Effect checks it.On #3728, the strategy is different because there's no single
state
object so there's nosetStateAndPersist
function. Instead there's a function calledpersistNextUpdate
which sets the sameisDirty.current = true
ref. I'm not a big fan of this approach because it's a bit hard to tell which exactly state update will be persisted. It also seems easy to add asetState
call somewhere in a different function, assume it's taken care of by an earlierpersistNextUpdate
call, and then to lose that earlier call due to some refactoring. So I'd like to enforce that the decision to persist is close to the state update.The strategy I'm taking in this PR is different from both of these approaches. Instead of tracking a separate ref, I track the need to persist in the state object itself as a mutable field.
There is no
isDirty
ref. Instead, the effect checks the latest committed state:This ensures that any state updates to
state.accounts
andstate.currentAccount
get persisted as long as they have theneedsPersist: true
tag. I'm keeping itfalse
on updates originating from the tab sync.Note that if you have a
needsPersist: true
update that hasn't been processed yet, immediately followed by aneedsPersist: false
update, neither of them will get persisted because the latest version wins. This is different from the current behavior whereisDirty.current
beingtrue
will cause the next committed update to be persisted. However I think that's fine (and maybe even good?) because the only reason you could get aneedsPersist: false
update is if you did something in another tab — and in that case the other-tab-originating update is fresher anyway. So it kind of makes sense that we only ever want to persist the latest state — and only if that specific state is marked to be persisted.I plan to port this change to #3728 as well if we get it into main.
Test Plan
Put logs next to persistence. Verify changes get persisted as before. Verify switching account, logging out, logging in works. Verify logging out or switching accounts in another tab switches the current tab.