Skip to content

Conversation

@vbudhram
Copy link
Contributor

@vbudhram vbudhram commented Dec 9, 2025

Because

  • The Nimbus context was not reactively updating when users changed their metrics preferences in localStorage
  • Metrics opt-in/opt-out changes required a full page reload to take effect, leading to stale experiment state
  • Direct localStorage reads in useEffect don't trigger re-renders when values change in the same tab

This pull request

  • Adds useLocalStorageSync hook using React's useSyncExternalStore for reactive localStorage monitoring
  • Dispatches custom localStorageChange events when Storage class modifies localStorage values
  • Refactors NimbusContext to use useLocalStorageSync for tracking currentAccountUid and accounts data

Issue that this pull request solves

Closes: https://mozilla-hub.atlassian.net/browse/FXA-12738

Checklist

  • My commit is GPG signed.
  • [ x] If applicable, I have modified or added tests which pass locally.
  • I have added necessary documentation (if appropriate).
  • I have verified that my changes render correctly in RTL (if appropriate).

Other information (Optional)

This change improves the reactivity of the Nimbus experimentation system by ensuring that metrics preference changes are immediately reflected without requiring page reloads. The implementation uses React 18's useSyncExternalStore API for proper external state synchronization.

@vbudhram vbudhram self-assigned this Dec 17, 2025
@vbudhram vbudhram marked this pull request as ready for review December 17, 2025 18:02
@vbudhram vbudhram requested a review from a team as a code owner December 17, 2025 18:02
@vbudhram vbudhram requested a review from LZoog December 19, 2025 17:07
Copy link
Contributor

@LZoog LZoog left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code LGTM, + tested locally and it works!

* }, [currentAccountUid]);
* ```
*/
export function useLocalStorageSync(key: string) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

// Get metricsEnabled from accounts object, safely handling undefined values
const accountMetricsEnabled = useMemo(() => {
if (!currentAccountUid || !accounts) {
return undefined;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I'm not signed into an account, this value is undefined and so the Nimbus experiments don't get fetched. Should this be true instead?

Also, do you plan to address the 1. and 2. points of the ticket in this PR? I think this only covers the 3rd case, but the other 2 should be easy at least if you want to do them here or in a quick follow up.

Copy link
Contributor Author

@vbudhram vbudhram Dec 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe 2. was already done

If I'm not signed into an account, this value is undefined and so the Nimbus experiments don't get fetched. Should this be true instead?

I can change it to true it is confusing, the experiments should get called since the check is undefined === false below

accountMetricsEnabled,
]);

const value: NimbusContextValue = useMemo(() => ({
Copy link
Contributor

@LZoog LZoog Dec 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, when I navigate from email-first to sign-in after a fresh /clear, I get this error in the console:

Image

I wouldn't expect this to rerender at this point, given local storage hasn't changed yet? Or maybe it did change due to Glean entry stuff and we only need to rerender on currentAccountUid and not accounts if that changes there? Looking at getAccountInfo in Signin Container, I guess we do update it with setCurrentAccount at this point, but we don't have the UID so we shouldn't rerender there yet 🤔

I don't see the error again at least when I enter the account password and the useEffect correctly runs, it seems to work, which is neat! 🎉

... Though, when I signed into an unverified account and confirmed it, when I was redirected to Settings with that account, the useEffect reran again for some reason, and accountsMetricsDisabled is set to undefined.
image

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@LZoog I havent been able to reproduce this :/

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants