Skip to content

fix(markets): keep the current market visible in the switcher - #3130

Open
shivam-V8 wants to merge 2 commits into
aave:mainfrom
shivam-V8:fix/3128-current-legacy-market-visible
Open

shivam-V8 wants to merge 2 commits into
aave:mainfrom
shivam-V8:fix/3128-current-legacy-market-visible

Conversation

@shivam-V8

@shivam-V8 shivam-V8 commented Oct 11, 2026 •

Copy link
Copy Markdown

The legacy group only renders while "Show legacy markets" is on, and that flag reset to false on every mount. A user viewing a legacy market therefore could not see it in the switcher and nothing appeared selected. Default the flag from the market being viewed instead.

Closes #3128

General Changes

  • Fixes bug: the current market is missing from the market switcher when it is a legacy market #3128: when the active market is a legacy one (Gnosis, Sonic, Scroll, Metis, ZKsync, Soneium, EtherFi), opening the market switcher did not list it and nothing appeared selected — the header read "Gnosis" while the list behaved as though Gnosis did not exist.
  • The "Show legacy markets" group is now shown whenever the market being viewed is itself legacy, both at mount and when the market changes afterwards.

Developer Notes

Root cause — showLegacy was initialised to false and never persisted, so it reset on every mount regardless of the market being viewed. The legacy group only renders while that flag is on, and isSelected can only highlight an item that is rendered.

Change — two parts:

  1. The state declaration moves below the useRootStore reads (at its previous position currentMarket is not yet defined, so referencing it there is a temporal-dead-zone error) and derives its default from the current market, reusing the existing module-level getMarketCategory helper.
  2. A sync effect keeps that default correct after mount.
const [showLegacy, setShowLegacy] = useState(() => getMarketCategory(currentMarket) === 'legacy');

useEffect(() => {
  if (getMarketCategory(currentMarket) === 'legacy') {
    setShowLegacy(true);
  }
}, [currentMarket]);

The effect is not redundant with the initialiser. setQueryParameter uses Router.push(..., { shallow: true }), so a market change never remounts the header; and src/store/root.ts hydrates currentMarket from ?marketName/localStorage inside document.onreadystatechange, i.e. after the store initialises to availableMarkets[0] (Core, non-legacy). Without the effect, a switcher that mounts before hydration latches a stale false on exactly the deep-link path this issue describes. The initialiser is kept so there is no flash when the market is already known at mount.

This came from the automated review on the first commit; the finding was accepted and 077a5e6 addresses it.

Behaviour worth flagging — the effect only ever sets true, so once a legacy market has been visited the section stays expanded for the rest of that mount, even after switching to a non-legacy market. A fresh page load on a non-legacy market still starts collapsed. Mirroring both ways would override a user's deliberate "on" toggle whenever they moved to a non-legacy market, which seemed worse — happy to switch to the stricter behaviour if you prefer it.

tsc --noEmit and next lint are clean for this file (exhaustivjest baseline is unchanged.

Relationship to #3129 — independent. That PR fixes the search half of the same area (#3127) and touches the import block, noResults and the legacyrender guard; this one touches the React import and the state declaration. They merge in either order. No unit test here for the same reason: the pure helpers introduced by #3129 live in a file that does not exisng it here would make the two PRs conflict. Happy to follow up with a test once #3129 lands.

Pre-existing failures — the 4 jest suites in src/utils/ that fail on main (a wagmi/chains import issue) are unaffected.

Reviewer Checklist

Please ensure you, as the reviewer(s), have gone through this checklist to ensure that the code changes are ready to ship safely and to help mitigate
any downstream issues that may occur.

  • End-to-end tests are passing without any errors
  • Code changes do not significantly increase the application bundle size
  • If there are new 3rd-party packages, they do not introdeats
  • If there are new environment variables being added, they have been added to the .env.example file as well as the pertinant .github/actions/* files
  • There are no CI changes, or they have been approved by the DevOps and Engineering team(s)

… is legacy

The legacy group only renders while "Show legacy markets" is on, and that flag reset
to false on every mount. A user viewing a legacy market therefore could not see it in
the switcher and nothing appeared selected. Default the flag from the market being
viewed instead.

Closes aave#3128
@vercel

vercel Bot commented Oct 11, 2026

Copy link
Copy Markdown

@Krshivam25 is attempting to deploy a commit to the Aave Team on Vercel.

A member of the Team first needs to authorize it.

@aave-code-review aave-code-review Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This review covered an earlier commit. It is superseded by the review for 077a5e67.

const toggleFavoriteMarket = useRootStore((store) => store.toggleFavoriteMarket);
const favoriteMarkets = useRootStore((store) => store.favoriteMarkets);

// A legacy market the user is actually on must not be missing from the list: the legacy

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Accepted — good catch, and the case is stronger than described.

setQueryParameter uses Router.push(..., { shallow: true }), so a market change never remounts the header. On top of that, src/store/root.ts hydrates currentMarket from ?marketName/localStorage inside document.onreadystatechange, i.e. after the store initialises to availableMarkets[0] (Core, non-legacy). If the switcher mounts before that fires, the initialiser latches false on exactly the deep-link path #3128 is about. My manual check only passed because hydration won that race locally.

Applied your suggestion. The effect only ever sets true and only on a currentMarket change, so a deliberate toggle-off is still respected while the user stays on that market; the lazy initialiser is kept so there's no flash when the market is already known at mount.

One behaviour worth flagging: because the effect never sets false, once a legacy market has been visited the section stays expanded for the rest of that mount, even after switching to a non-legacy market (a fresh page load still starts collapsed). I verified all three paths locally. Mirroring both ways would override a user's deliberate "on" toggle whenever they moved to a non-legacy market, which seemed worse — happy to change it if you'd prefer the stricter behaviour.

The lazy initialiser runs only at mount, but the header survives shallow market
changes and the store hydrates marketName from the URL after the first render, so
the default could latch a stale false and hide the active legacy market again.
Sync it whenever the current market becomes legacy.
const toggleFavoriteMarket = useRootStore((store) => store.toggleFavoriteMarket);
const favoriteMarkets = useRootStore((store) => store.favoriteMarkets);

// A legacy market the user is actually on must not be missing from the list: the legacy

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Accepted — good catch, and the case is stronger than described.

setQueryParameter uses Router.push(..., { shallow: true }), so a market change never remounts the header. On top of that, src/store/root.ts hydrates currentMarket from ?marketName/localStorage inside document.onreadystatechange, i.e. after the store initialises to availableMarkets[0] (Core, non-legacy). If the switcher mounts before that fires, the initialiser latches false on exactly the deep-link path #3128 is about. My manual check only passed because hydration won that race locally.

Applied your suggestion. The effect only ever sets true and only on a currentMarket change, so a deliberate toggle-off is still respected while the user stays on that market; the lazy initialiser is kept so there's no flash when the market is already known at mount.

One behaviour worth flagging: because the effect never sets false, once a legacy market has been visited the section stays expanded for the rest of that mount, even after switching to a non-legacy market (a fresh page load still starts collapsed). I verified all three paths locally. Mirroring both ways would override a user's deliberate "on" toggle whenever they moved to a non-legacy market, which seemed worse — happy to change it if you'd prefer the stricter behaviour.

This branch has not been deployed

No deployments
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.

bug: the current market is missing from the market switcher when it is a legacy market

2 participants