Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf: Create custom spans for account overview tabs #28086

Merged
merged 30 commits into from
Nov 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
8ecf0b2
Revert "feat: codefence Account Watcher for flask (#27543)"
MajorLift Oct 23, 2024
9924b50
Add trace names for account list item and account overview tab
MajorLift Oct 24, 2024
a4c46b7
Add trace calls for `AccountListItem` span
MajorLift Oct 24, 2024
394d487
Add trace calls for `AccountOverviewTab` span
MajorLift Oct 24, 2024
39cc6f2
Abort `AccountListItem` span if account tab is switched
MajorLift Oct 24, 2024
656dfdb
Abort `AccountOverviewTab` span if account tab is switched before cur…
MajorLift Oct 25, 2024
9f90b84
Abort `AccountOverviewTab` span if new account is selected in account…
MajorLift Oct 25, 2024
04d0694
Abort `AccountListItem` span if new account is selected in account li…
MajorLift Oct 28, 2024
ccc6a34
Revert "Revert "feat: codefence Account Watcher for flask (#27543)""
MajorLift Oct 28, 2024
e9b9aef
Remove `AccountOverviewTab`, `AccountListItem` spans
MajorLift Oct 30, 2024
c53f8bb
Define custom spans `AccountOverview{AssetList,Nfts,Activity}Tab`
MajorLift Oct 30, 2024
b9fa09e
Place `endTrace` calls for new custom spans in corresponding `Account…
MajorLift Oct 30, 2024
b79a95e
Define utility functions `{start,end}Traces` for batch handling of tr…
MajorLift Oct 30, 2024
b5046fd
Define new redux selector `getDefaultHomeActiveTabName`
MajorLift Oct 30, 2024
694e73d
Trigger and terminate custom spans when clicking on account list item…
MajorLift Oct 30, 2024
c0f9811
`endTrace` calls for "Tokens" and "Nfts" tab conditionally trigger wh…
MajorLift Oct 30, 2024
21bbcf6
Trigger `AccountOverviewAssetListTab` span when detected token select…
MajorLift Oct 30, 2024
4fa73c1
Nfts tab span termination also requires `nftsStillFetchingIndication`…
MajorLift Nov 1, 2024
a5c2ae2
Define types, constants for account overview tabs and replace `fromTa…
MajorLift Nov 1, 2024
6bbef8e
Revert "Define utility functions `{start,end}Traces` for batch handli…
MajorLift Nov 1, 2024
26b2031
Merge branch 'develop' into jongsun/perf/trace/241009-account-watcher
MajorLift Nov 1, 2024
f49728b
Linter fixes
MajorLift Nov 1, 2024
0d914ec
Align types for `defaultHomeActiveTabName`
MajorLift Nov 1, 2024
9c33083
Fix import order
MajorLift Nov 1, 2024
cfcc492
Remove `AccountOverviewTabKeys` enum union type
MajorLift Nov 6, 2024
df17187
Move `detectNfts` dispatch call out of component library and into `ac…
MajorLift Nov 6, 2024
f3c989b
Add `endTrace` call for case where `NftsTab` displays the empty banner
MajorLift Nov 11, 2024
3790fc4
Merge branch 'develop' into jongsun/perf/trace/241009-account-watcher
MajorLift Nov 11, 2024
2718cc4
Merge branch 'develop' into jongsun/perf/trace/241009-account-watcher
MajorLift Nov 12, 2024
7eae322
Remove NftsTab `endTrace` call that triggers prematurely
MajorLift Nov 13, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions app/scripts/controllers/app-state-controller.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
ORIGIN_METAMASK,
POLLING_TOKEN_ENVIRONMENT_TYPES,
} from '../../../shared/constants/app';
import { AccountOverviewTabKey } from '../../../shared/constants/app-state';
import { AppStateController } from './app-state-controller';
import type {
AllowedActions,
Expand Down Expand Up @@ -209,9 +210,11 @@ describe('AppStateController', () => {

describe('setDefaultHomeActiveTabName', () => {
it('sets the default home tab name', () => {
appStateController.setDefaultHomeActiveTabName('testTabName');
appStateController.setDefaultHomeActiveTabName(
AccountOverviewTabKey.Activity,
);
expect(appStateController.store.getState().defaultHomeActiveTabName).toBe(
'testTabName',
AccountOverviewTabKey.Activity,
);
});
});
Expand Down
7 changes: 5 additions & 2 deletions app/scripts/controllers/app-state-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
import { DEFAULT_AUTO_LOCK_TIME_LIMIT } from '../../../shared/constants/preferences';
import { LastInteractedConfirmationInfo } from '../../../shared/types/confirm';
import { SecurityAlertResponse } from '../lib/ppom/types';
import { AccountOverviewTabKey } from '../../../shared/constants/app-state';
import type {
Preferences,
PreferencesControllerGetStateAction,
Expand All @@ -35,7 +36,7 @@ import type {
export type AppStateControllerState = {
timeoutMinutes: number;
connectedStatusPopoverHasBeenShown: boolean;
defaultHomeActiveTabName: string | null;
defaultHomeActiveTabName: AccountOverviewTabKey | null;
browserEnvironment: Record<string, string>;
popupGasPollTokens: string[];
notificationGasPollTokens: string[];
Expand Down Expand Up @@ -326,7 +327,9 @@ export class AppStateController extends EventEmitter {
*
* @param defaultHomeActiveTabName - the tab name
*/
setDefaultHomeActiveTabName(defaultHomeActiveTabName: string | null): void {
setDefaultHomeActiveTabName(
defaultHomeActiveTabName: AccountOverviewTabKey | null,
): void {
this.store.updateState({
defaultHomeActiveTabName,
});
Expand Down
20 changes: 20 additions & 0 deletions shared/constants/app-state.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { TraceName } from '../lib/trace';
import { MetaMetricsEventName } from './metametrics';

export enum AccountOverviewTabKey {
Tokens = 'tokens',
Nfts = 'nfts',
Activity = 'activity',
}

export const ACCOUNT_OVERVIEW_TAB_KEY_TO_METAMETRICS_EVENT_NAME_MAP = {
[AccountOverviewTabKey.Tokens]: MetaMetricsEventName.TokenScreenOpened,
[AccountOverviewTabKey.Nfts]: MetaMetricsEventName.NftScreenOpened,
[AccountOverviewTabKey.Activity]: MetaMetricsEventName.ActivityScreenOpened,
} as const;

export const ACCOUNT_OVERVIEW_TAB_KEY_TO_TRACE_NAME_MAP = {
[AccountOverviewTabKey.Tokens]: TraceName.AccountOverviewAssetListTab,
[AccountOverviewTabKey.Nfts]: TraceName.AccountOverviewNftsTab,
[AccountOverviewTabKey.Activity]: TraceName.AccountOverviewActivityTab,
} as const;
3 changes: 3 additions & 0 deletions shared/lib/trace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ import { log as sentryLogger } from '../../app/scripts/lib/setupSentry';
*/
export enum TraceName {
AccountList = 'Account List',
AccountOverviewAssetListTab = 'Account Overview Asset List Tab',
AccountOverviewNftsTab = 'Account Overview Nfts Tab',
AccountOverviewActivityTab = 'Account Overview Activity Tab',
BackgroundConnect = 'Background Connect',
DeveloperTest = 'Developer Test',
FirstRender = 'First Render',
Expand Down
7 changes: 7 additions & 0 deletions ui/components/app/assets/nfts/nfts-tab/nfts-tab.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import {
} from '../../../../../../shared/constants/metametrics';
import { getCurrentLocale } from '../../../../../ducks/locale/locale';
import Spinner from '../../../../ui/spinner';
import { endTrace, TraceName } from '../../../../../../shared/lib/trace';

export default function NftsTab() {
const useNftDetection = useSelector(getUseNftDetection);
Expand Down Expand Up @@ -93,6 +94,12 @@ export default function NftsTab() {
currentLocale,
]);

useEffect(() => {
if (!nftsLoading && !nftsStillFetchingIndication) {
endTrace({ name: TraceName.AccountOverviewNftsTab });
}
}, [nftsLoading, nftsStillFetchingIndication]);

Comment on lines +97 to +102
Copy link
Contributor

Choose a reason for hiding this comment

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

From https://react.dev/learn/you-might-not-need-an-effect#recap

If you can calculate something during render, you don’t need an Effect.

useEffect to run code "when this variable changes" is done A LOT, but it's actually an anti-pattern

This comment was marked as outdated.

Copy link
Contributor Author

@MajorLift MajorLift Nov 5, 2024

Choose a reason for hiding this comment

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

Applied, but with some questions: Wouldn't this be a case where useEffect is warranted since we're interfacing with an external/non-local system and triggering a side effect that depends on reactive variables?

I'm not sure if introducing impure logic to the top-level scope of a react component is in keeping with the article's recommendations. This usage also doesn't seem to fall under any of the example cases discussed in the article (no computations, no altering state in this or any relative component, no event handlers, etc.).

That said, removing the useEffect hooks doesn't seem to trigger extra re-renders or cause malfunctions, so this might be more a question of principle rather than practicality. Still would be nice to understand what the best practice is here (e.g. should we also remove useEffect hooks around trackEvent calls?).

Copy link
Contributor Author

@MajorLift MajorLift Nov 5, 2024

Choose a reason for hiding this comment

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

I've gone back to using useEffect hooks while implementing the additional spans:

I tried removing them, but ran into issues where the spans were not behaving as intended e.g. FCP lasting longer than FMP, FMP lasting longer than fully loaded.

Copy link
Contributor Author

@MajorLift MajorLift Nov 6, 2024

Choose a reason for hiding this comment

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

I reviewed the react docs in more detail, and it seems to indicate that trace/endTrace calls must always be placed inside useEffect hooks, unless triggered by an event:

  1. Sending analytics is a use case for useEffect that's explicitly covered in the docs. trace, endTrace are side effects that synchronize with an external system (i.e. sentry). They're also implemented with POST requests, which are definitely Effects.

Some components need to synchronize with external systems. For example, you might want to ... send an analytics log when a component appears on the screen.
https://react.dev/learn/synchronizing-with-effects#sending-analytics

  1. Because these endTrace calls are measuring load time, their only trigger is the component being displayed. They're also conditionally dependent on reactive values in the component's rendering logic, which leads me to question whether they can be guaranteed to execute correctly or deterministically, if they're not suspended by useEffect until after the render completes.

When you’re not sure whether some code should be in an Effect or in an event handler, ask yourself why this code needs to run. Use Effects only for code that should run because the component was displayed to the user. In this example, the notification should appear because the user pressed the button, not because the page was displayed!
https://react.dev/learn/you-might-not-need-an-effect#sharing-logic-between-event-handlers

The analytics POST request should remain in an Effect. This is because the reason to send the analytics event is that the form was displayed.
https://react.dev/learn/you-might-not-need-an-effect#sending-a-post-request

(useEffect) tells React to execute it later, after rendering, when side effects are allowed.
https://react.dev/learn/keeping-components-pure#where-you-_can_-cause-side-effects

  1. Re-renders aren't the only performance consideration here. Removing useEffect makes its inner function re-run on every render instead of only when the dependencies are updated. Avoiding these wasteful re-runs is the purpose of populating the dependency array in useEffect hooks.

  2. To my understanding, ensuring that a react component remains pure is a higher priority concern than reducing re-renders. Directly introducing a side effect into the component body goes beyond the prescribed "last resort" of using useEffect and brings us completely outside of the react paradigm. I don't see that an analytics logging call warrants such a measure.

If you’ve exhausted all other options and can’t find the right event handler for your side effect, you can still attach it to your returned JSX with a useEffect call in your component. ... However, this approach should be your last resort.
https://react.dev/learn/keeping-components-pure#where-you-_can_-cause-side-effects
https://react.dev/learn/keeping-components-pure#why-does-react-care-about-purity

  1. useEffect works by reacting to reactive values, and useEffect dependencies are reactive values, meaning an effect triggering a re-render in response to a reactive value being updated is expected behavior, not a performance penalty. We shouldn't be removing useEffect just because they cause re-renders, without examining whether they're doing so unnecessarily, or as an unavoidable part of the hook's core functionality.

  2. The following use cases for removing an Effect do not seem to apply here, since we're not transforming data, performing a pure calculation, or producing any cacheable artifact.

If you can calculate something during render, you don’t need an Effect.

You don’t need Effects to transform data for rendering.

https://react.dev/learn/you-might-not-need-an-effect

Edit: Upon discussion..

  • Use useEffect for trace calls that rely on reactive values in render logic.
  • There still seem to be superfluous re-renders. Investigate.

if (!hasAnyNfts && nftsStillFetchingIndication) {
return (
<Box className="nfts-tab__loading">
Expand Down
9 changes: 8 additions & 1 deletion ui/components/app/assets/token-list/token-list.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { ReactNode, useMemo } from 'react';
import React, { ReactNode, useEffect, useMemo } from 'react';
import { shallowEqual, useSelector } from 'react-redux';
import TokenCell from '../token-cell';
import { useI18nContext } from '../../../../hooks/useI18nContext';
Expand All @@ -19,6 +19,7 @@ import {
import { useAccountTotalFiatBalance } from '../../../../hooks/useAccountTotalFiatBalance';
import { getConversionRate } from '../../../../ducks/metamask/metamask';
import { useNativeTokenBalance } from '../asset-list/native-token/use-native-token-balance';
import { endTrace, TraceName } from '../../../../../shared/lib/trace';

type TokenListProps = {
onTokenClick: (arg: string) => void;
Expand Down Expand Up @@ -66,6 +67,12 @@ export default function TokenList({
contractExchangeRates,
]);

useEffect(() => {
if (!loading) {
endTrace({ name: TraceName.AccountOverviewAssetListTab });
}
}, [loading]);
MajorLift marked this conversation as resolved.
Show resolved Hide resolved

return loading ? (
<Box
display={Display.Flex}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import Popover from '../../../ui/popover';
import Box from '../../../ui/box';
import Button from '../../../ui/button';
import DetectedTokenDetails from '../detected-token-details/detected-token-details';
import { trace, endTrace, TraceName } from '../../../../../shared/lib/trace';

const DetectedTokenSelectionPopover = ({
tokensListDetected,
Expand Down Expand Up @@ -64,7 +65,11 @@ const DetectedTokenSelectionPopover = ({
<Button
className="detected-token-selection-popover__import-button"
type="primary"
onClick={onImport}
onClick={() => {
endTrace({ name: TraceName.AccountOverviewAssetListTab });
trace({ name: TraceName.AccountOverviewAssetListTab });
onImport();
}}
disabled={selectedTokens.length === 0}
>
{t('importWithCount', [`(${selectedTokens.length})`])}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import React, {
useCallback,
Fragment,
useContext,
useEffect,
} from 'react';
import PropTypes from 'prop-types';
import { useSelector } from 'react-redux';
Expand Down Expand Up @@ -53,6 +54,7 @@ import { getMultichainAccountUrl } from '../../../helpers/utils/multichain/block
import { MetaMetricsContext } from '../../../contexts/metametrics';
import { useMultichainSelector } from '../../../hooks/useMultichainSelector';
import { getMultichainNetwork } from '../../../selectors/multichain';
import { endTrace, TraceName } from '../../../../shared/lib/trace';

const PAGE_INCREMENT = 10;

Expand Down Expand Up @@ -258,6 +260,11 @@ export default function TransactionList({
// Check if the current account is a bitcoin account
const isBitcoinAccount = useSelector(isSelectedInternalAccountBtc);
const trackEvent = useContext(MetaMetricsContext);

useEffect(() => {
endTrace({ name: TraceName.AccountOverviewActivityTab });
}, []);

const multichainNetwork = useMultichainSelector(
getMultichainNetwork,
selectedAccount,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ import {
getOriginOfCurrentTab,
getSelectedInternalAccount,
getUpdatedAndSortedAccounts,
getDefaultHomeActiveTabName,
///: BEGIN:ONLY_INCLUDE_IF(solana)
getIsSolanaSupportEnabled,
///: END:ONLY_INCLUDE_IF
Expand Down Expand Up @@ -114,7 +115,11 @@ import {
AccountConnections,
MergedInternalAccount,
} from '../../../selectors/selectors.types';
import { endTrace, TraceName } from '../../../../shared/lib/trace';
import { endTrace, trace, TraceName } from '../../../../shared/lib/trace';
import {
ACCOUNT_OVERVIEW_TAB_KEY_TO_TRACE_NAME_MAP,
AccountOverviewTabKey,
} from '../../../../shared/constants/app-state';
///: BEGIN:ONLY_INCLUDE_IF(solana)
import {
SOLANA_WALLET_NAME,
Expand Down Expand Up @@ -251,6 +256,9 @@ export const AccountListMenu = ({
),
[updatedAccountsList, allowedAccountTypes],
);
const defaultHomeActiveTabName: AccountOverviewTabKey = useSelector(
getDefaultHomeActiveTabName,
);
///: BEGIN:ONLY_INCLUDE_IF(keyring-snaps)
const addSnapAccountEnabled = useSelector(getIsAddSnapAccountEnabled);
///: END:ONLY_INCLUDE_IF
Expand Down Expand Up @@ -340,6 +348,16 @@ export const AccountListMenu = ({
location: 'Main Menu',
},
});
endTrace({
name: ACCOUNT_OVERVIEW_TAB_KEY_TO_TRACE_NAME_MAP[
defaultHomeActiveTabName
],
});
trace({
name: ACCOUNT_OVERVIEW_TAB_KEY_TO_TRACE_NAME_MAP[
defaultHomeActiveTabName
],
});
dispatch(setSelectedAccount(account.address));
};
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
} from './account-overview-btc';

const defaultProps: AccountOverviewBtcProps = {
defaultHomeActiveTabName: '',
defaultHomeActiveTabName: null,
onTabClick: jest.fn(),
setBasicFunctionalityModalOpen: jest.fn(),
onSupportLinkClick: jest.fn(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ describe('AccountOverviewEth', () => {
});
it('shows all tabs', () => {
const { queryByTestId } = render({
defaultHomeActiveTabName: '',
defaultHomeActiveTabName: null,
onTabClick: jest.fn(),
setBasicFunctionalityModalOpen: jest.fn(),
onSupportLinkClick: jest.fn(),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import React, { useCallback, useContext, useMemo } from 'react';
import { useDispatch } from 'react-redux';
import { useHistory } from 'react-router-dom';
import { endTrace, trace } from '../../../../shared/lib/trace';
import { useI18nContext } from '../../../hooks/useI18nContext';
import { ASSET_ROUTE } from '../../../helpers/constants/routes';
import {
///: BEGIN:ONLY_INCLUDE_IF(build-main)
SUPPORT_LINK,
///: END:ONLY_INCLUDE_IF
} from '../../../../shared/lib/ui-utils';
import {
MetaMetricsEventCategory,
MetaMetricsEventName,
} from '../../../../shared/constants/metametrics';
import { MetaMetricsEventCategory } from '../../../../shared/constants/metametrics';
import { MetaMetricsContext } from '../../../contexts/metametrics';
import NftsTab from '../../app/assets/nfts/nfts-tab';
import AssetList from '../../app/assets/asset-list';
Expand All @@ -37,6 +36,12 @@ import {
///: BEGIN:ONLY_INCLUDE_IF(build-mmi)
import InstitutionalHomeFooter from '../../../pages/home/institutional/institutional-home-footer';
///: END:ONLY_INCLUDE_IF
import {
ACCOUNT_OVERVIEW_TAB_KEY_TO_METAMETRICS_EVENT_NAME_MAP,
ACCOUNT_OVERVIEW_TAB_KEY_TO_TRACE_NAME_MAP,
AccountOverviewTabKey,
} from '../../../../shared/constants/app-state';
import { detectNfts } from '../../../store/actions';
import { AccountOverviewCommonProps } from './common';

export type AccountOverviewTabsProps = AccountOverviewCommonProps & {
Expand All @@ -60,6 +65,7 @@ export const AccountOverviewTabs = ({
const history = useHistory();
const t = useI18nContext();
const trackEvent = useContext(MetaMetricsContext);
const dispatch = useDispatch();

const tabProps = useMemo(
() => ({
Expand All @@ -69,24 +75,24 @@ export const AccountOverviewTabs = ({
[],
);

const getEventFromTabName = (tabName: string) => {
switch (tabName) {
case 'nfts':
return MetaMetricsEventName.NftScreenOpened;
case 'activity':
return MetaMetricsEventName.ActivityScreenOpened;
default:
return MetaMetricsEventName.TokenScreenOpened;
}
};

const handleTabClick = useCallback(
(tabName: string) => {
(tabName: AccountOverviewTabKey) => {
onTabClick(tabName);
if (tabName === AccountOverviewTabKey.Nfts) {
dispatch(detectNfts());
}
trackEvent({
category: MetaMetricsEventCategory.Home,
event: getEventFromTabName(tabName),
event: ACCOUNT_OVERVIEW_TAB_KEY_TO_METAMETRICS_EVENT_NAME_MAP[tabName],
});
if (defaultHomeActiveTabName) {
endTrace({
name: ACCOUNT_OVERVIEW_TAB_KEY_TO_TRACE_NAME_MAP[
defaultHomeActiveTabName
],
});
}
trace({ name: ACCOUNT_OVERVIEW_TAB_KEY_TO_TRACE_NAME_MAP[tabName] });
},
[onTabClick],
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const render = (props: AccountOverviewUnknownProps) => {
describe('AccountOverviewUnknown', () => {
it('shows only the activity tab', () => {
const { queryByTestId } = render({
defaultHomeActiveTabName: '',
defaultHomeActiveTabName: null,
onTabClick: jest.fn(),
setBasicFunctionalityModalOpen: jest.fn(),
onSupportLinkClick: jest.fn(),
Expand Down
4 changes: 3 additions & 1 deletion ui/components/multichain/account-overview/common.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { AccountOverviewTabKey } from '../../../../shared/constants/app-state';

export type AccountOverviewCommonProps = {
onTabClick: (tabName: string) => void;
setBasicFunctionalityModalOpen: () => void;
///: BEGIN:ONLY_INCLUDE_IF(build-main)
onSupportLinkClick: () => void;
///: END:ONLY_INCLUDE_IF
defaultHomeActiveTabName: string;
defaultHomeActiveTabName: AccountOverviewTabKey | null;
};
7 changes: 0 additions & 7 deletions ui/components/ui/tabs/tabs.component.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import { useDispatch } from 'react-redux';
import Box from '../box';
import {
BackgroundColor,
DISPLAY,
JustifyContent,
} from '../../../helpers/constants/design-system';
import { detectNfts } from '../../../store/actions';

const Tabs = ({
defaultActiveTabKey,
Expand All @@ -22,7 +20,6 @@ const Tabs = ({
const _getValidChildren = () => {
return React.Children.toArray(children).filter(Boolean);
};
const dispatch = useDispatch();

/**
* Returns the index of the child with the given key
Expand All @@ -44,10 +41,6 @@ const Tabs = ({
setActiveTabIndex(tabIndex);
onTabClick?.(tabKey);
}

if (tabKey === 'nfts') {
dispatch(detectNfts());
}
};

const renderTabs = () => {
Expand Down
4 changes: 4 additions & 0 deletions ui/selectors/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -1299,6 +1299,10 @@ export function getOriginOfCurrentTab(state) {
return state.activeTab.origin;
}

export function getDefaultHomeActiveTabName(state) {
return state.metamask.defaultHomeActiveTabName;
}

export function getIpfsGateway(state) {
return state.metamask.ipfsGateway;
}
Expand Down