Skip to content

Commit ddb32ea

Browse files
committed
Fix logical rule violations
1 parent 047d462 commit ddb32ea

File tree

20 files changed

+260
-150
lines changed

20 files changed

+260
-150
lines changed

ui/components/app/currency-input/hooks/useProcessNewDecimalValue.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ export default function useProcessNewDecimalValue(
1616
isTokenPrimary: boolean,
1717
tokenToFiatConversionRate: Numeric | undefined,
1818
) {
19+
const tokenToFiatConversionRateToString =
20+
tokenToFiatConversionRate?.toString();
21+
1922
return useCallback(
2023
(newDecimalValue: string, isTokenPrimaryOverride?: boolean) => {
2124
let newFiatDecimalValue, newTokenDecimalValue;
@@ -55,6 +58,7 @@ export default function useProcessNewDecimalValue(
5558

5659
return { newFiatDecimalValue, newTokenDecimalValue };
5760
},
58-
[tokenToFiatConversionRate?.toString(), isTokenPrimary, assetDecimals],
61+
// `tokenToFiatConversionRate` intentionally excluded to ensure that re-renders are only triggered when conversion rate value actually changes.
62+
[tokenToFiatConversionRateToString, isTokenPrimary, assetDecimals],
5963
);
6064
}

ui/components/app/currency-input/hooks/useTokenExchangeRate.tsx

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useMemo, useState } from 'react';
1+
import { useMemo, useState, useEffect } from 'react';
22
import { toChecksumAddress } from 'ethereumjs-util';
33
import { shallowEqual, useSelector } from 'react-redux';
44
import { getCurrentChainId } from '../../../../../shared/modules/selectors/networks';
@@ -41,6 +41,19 @@ export default function useTokenExchangeRate(
4141
Record<string, ExchangeRate>
4242
>({});
4343

44+
const contractExchangeRate = tokenAddress
45+
? contractExchangeRates[tokenAddress] || exchangeRates[tokenAddress]
46+
: undefined;
47+
48+
useEffect(() => {
49+
if (!contractExchangeRate && tokenAddress) {
50+
setExchangeRates((prev) => ({
51+
...prev,
52+
[tokenAddress]: LOADING,
53+
}));
54+
}
55+
}, [contractExchangeRate, tokenAddress]);
56+
4457
return useMemo(() => {
4558
if (!selectedNativeConversionRate) {
4659
return undefined;
@@ -62,14 +75,7 @@ export default function useTokenExchangeRate(
6275
return undefined;
6376
}
6477

65-
const contractExchangeRate =
66-
contractExchangeRates[tokenAddress] || exchangeRates[tokenAddress];
67-
6878
if (!contractExchangeRate) {
69-
setExchangeRates((prev) => ({
70-
...prev,
71-
[tokenAddress]: LOADING,
72-
}));
7379
fetchTokenExchangeRates(nativeCurrency, [tokenAddress], chainId)
7480
.then((addressToExchangeRate) => {
7581
setExchangeRates((prev) => ({
@@ -95,6 +101,6 @@ export default function useTokenExchangeRate(
95101
nativeCurrency,
96102
tokenAddress,
97103
selectedNativeConversionRate,
98-
contractExchangeRates,
104+
contractExchangeRate,
99105
]);
100106
}

ui/components/app/qr-hardware-popover/base-reader.js

Lines changed: 46 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useEffect, useRef, useState } from 'react';
1+
import React, { useEffect, useRef, useState, useCallback } from 'react';
22
import log from 'loglevel';
33
import { URDecoder } from '@ngraveio/bc-ur';
44
import PropTypes from 'prop-types';
@@ -30,7 +30,7 @@ const BaseReader = ({
3030
const [urDecoder, setURDecoder] = useState(new URDecoder());
3131
const [progress, setProgress] = useState(0);
3232

33-
let permissionChecker = null;
33+
const permissionCheckerRef = useRef(null);
3434
const mounted = useRef(false);
3535

3636
const reset = () => {
@@ -40,29 +40,7 @@ const BaseReader = ({
4040
setProgress(0);
4141
};
4242

43-
const checkEnvironment = async () => {
44-
try {
45-
const { environmentReady } = await WebcamUtils.checkStatus();
46-
if (
47-
!environmentReady &&
48-
getEnvironmentType() !== ENVIRONMENT_TYPE_FULLSCREEN
49-
) {
50-
const currentUrl = new URL(window.location.href);
51-
const currentHash = currentUrl.hash;
52-
const currentRoute = currentHash ? currentHash.substring(1) : null;
53-
global.platform.openExtensionInBrowser(currentRoute);
54-
}
55-
} catch (e) {
56-
if (mounted.current) {
57-
setError(e);
58-
}
59-
}
60-
// initial attempt is required to trigger permission prompt
61-
// eslint-disable-next-line no-use-before-define
62-
return initCamera();
63-
};
64-
65-
const checkPermissions = async () => {
43+
const checkPermissions = useCallback(async () => {
6644
try {
6745
const { permissions } = await WebcamUtils.checkStatus();
6846
if (permissions) {
@@ -74,15 +52,52 @@ const BaseReader = ({
7452
setReady(READY_STATE.READY);
7553
} else if (mounted.current) {
7654
// Keep checking for permissions
77-
permissionChecker = setTimeout(checkPermissions, SECOND);
55+
permissionCheckerRef.current = setTimeout(checkPermissions, SECOND);
7856
setReady(READY_STATE.NEED_TO_ALLOW_ACCESS);
7957
}
8058
} catch (e) {
8159
if (mounted.current) {
8260
setError(e);
8361
}
8462
}
85-
};
63+
}, []);
64+
65+
const initCamera = useCallback(() => {
66+
try {
67+
checkPermissions();
68+
} catch (e) {
69+
if (!mounted.current) {
70+
return;
71+
}
72+
if (e.name === 'NotAllowedError') {
73+
log.info(`Permission denied: '${e}'`);
74+
setReady(READY_STATE.NEED_TO_ALLOW_ACCESS);
75+
} else {
76+
setError(e);
77+
}
78+
}
79+
}, [checkPermissions]);
80+
81+
const checkEnvironment = useCallback(async () => {
82+
try {
83+
const { environmentReady } = await WebcamUtils.checkStatus();
84+
if (
85+
!environmentReady &&
86+
getEnvironmentType() !== ENVIRONMENT_TYPE_FULLSCREEN
87+
) {
88+
const currentUrl = new URL(window.location.href);
89+
const currentHash = currentUrl.hash;
90+
const currentRoute = currentHash ? currentHash.substring(1) : null;
91+
global.platform.openExtensionInBrowser(currentRoute);
92+
}
93+
} catch (e) {
94+
if (mounted.current) {
95+
setError(e);
96+
}
97+
}
98+
// initial attempt is required to trigger permission prompt
99+
return initCamera();
100+
}, [initCamera]);
86101

87102
const handleScan = (data) => {
88103
try {
@@ -105,30 +120,14 @@ const BaseReader = ({
105120
}
106121
};
107122

108-
const initCamera = () => {
109-
try {
110-
checkPermissions();
111-
} catch (e) {
112-
if (!mounted.current) {
113-
return;
114-
}
115-
if (e.name === 'NotAllowedError') {
116-
log.info(`Permission denied: '${e}'`);
117-
setReady(READY_STATE.NEED_TO_ALLOW_ACCESS);
118-
} else {
119-
setError(e);
120-
}
121-
}
122-
};
123-
124123
useEffect(() => {
125124
mounted.current = true;
126125
checkEnvironment();
127126
return () => {
128127
mounted.current = false;
129-
clearTimeout(permissionChecker);
128+
clearTimeout(permissionCheckerRef.current);
129+
permissionCheckerRef.current = null;
130130
};
131-
// eslint-disable-next-line react-hooks/exhaustive-deps
132131
}, []);
133132

134133
useEffect(() => {
@@ -137,11 +136,10 @@ const BaseReader = ({
137136
} else if (ready === READY_STATE.NEED_TO_ALLOW_ACCESS) {
138137
checkPermissions();
139138
}
140-
// eslint-disable-next-line react-hooks/exhaustive-deps
141-
}, [ready]);
139+
}, [ready, checkPermissions, initCamera]);
142140

143141
const tryAgain = () => {
144-
clearTimeout(permissionChecker);
142+
clearTimeout(permissionCheckerRef.current);
145143
reset();
146144
checkEnvironment();
147145
};

ui/components/component-library/select-wrapper/select-wrapper.stories.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,8 +172,9 @@ UncontrolledValue.args = {
172172
};
173173

174174
export const UseSelectContext: StoryFn<typeof SelectWrapper> = (args) => {
175-
// Note that the SelectContext is being used inside a component, because the SelectContext needs to be called within the SelectWrapper component and not before
176175
const CustomClose = () => {
176+
// Note that the SelectContext is being used inside a component, because the SelectContext needs to be called within the SelectWrapper component and not before
177+
// eslint-disable-next-line react-compiler/react-compiler
177178
const { toggleUncontrolledOpen } = useSelectContext();
178179

179180
return (

ui/components/component-library/text-field/text-field.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ export const TextField: TextFieldComponent = React.forwardRef(
9393
// Check if an external ref (inputRef) is provided and is a ref object
9494
if (inputRef && 'current' in inputRef) {
9595
// Assign the input element reference to the external ref
96+
// TODO: Use `ref` prop instead. `forwardRef` is deprecated in React v19.
97+
// eslint-disable-next-line react-compiler/react-compiler
9698
inputRef.current = inputElementRef;
9799
}
98100
// Check if an external ref (inputRef) is a callback function

ui/components/multichain/asset-picker-amount/asset-picker-modal/hooks/useAssetMetadata.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { CaipAssetType, CaipChainId, Hex } from '@metamask/utils';
2+
import { useEffect } from 'react';
23
import { useSelector } from 'react-redux';
34
import { getUseExternalServices } from '../../../../../selectors';
45
import {
@@ -25,6 +26,13 @@ export const useAssetMetadata = (
2526
) => {
2627
const allowExternalServices = useSelector(getUseExternalServices);
2728

29+
useEffect(() => {
30+
return () => {
31+
abortControllerRef.current?.abort();
32+
abortControllerRef.current = null;
33+
};
34+
}, [abortControllerRef]);
35+
2836
const { value: assetMetadata } = useAsyncResult<
2937
| {
3038
address: Hex | CaipAssetType | string;
@@ -49,7 +57,7 @@ export const useAssetMetadata = (
4957
shouldFetchMetadata &&
5058
trimmedSearchQuery.length > 30
5159
) {
52-
abortControllerRef.current = new AbortController();
60+
abortControllerRef.current ??= new AbortController();
5361
const metadata = await fetchAssetMetadata(
5462
trimmedSearchQuery,
5563
chainId,

ui/components/ui/deprecated-networks/deprecated-networks.js

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,20 @@ export default function DeprecatedNetworks() {
7676
setIsClosed(true);
7777

7878
const networkConfiguration = networkConfigurations[chainId];
79-
networkConfiguration.rpcEndpoints[
80-
networkConfiguration.defaultRpcEndpointIndex
81-
].url = 'https://mainnet.aurora.dev';
82-
83-
await dispatch(updateNetwork(networkConfiguration));
79+
await dispatch(
80+
updateNetwork({
81+
...networkConfiguration,
82+
rpcEndpoints: {
83+
...networkConfiguration.rpcEndpoints,
84+
[networkConfiguration.defaultRpcEndpointIndex]: {
85+
...networkConfiguration.rpcEndpoints[
86+
networkConfiguration.defaultRpcEndpointIndex
87+
],
88+
url: 'https://mainnet.aurora.dev',
89+
},
90+
},
91+
}),
92+
);
8493
},
8594
};
8695
}

ui/components/ui/icon/preloader/preloader-icon.component.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ const Preloader = ({ className, size }) => (
1919
/>
2020
<mask
2121
id="mask0"
22+
// eslint-disable-next-line react/no-unknown-property
2223
mask-type="alpha"
2324
maskUnits="userSpaceOnUse"
2425
x="0"

ui/contexts/metametrics.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,7 @@ export function MetaMetricsProvider({ children }) {
206206

207207
// For backwards compatibility, attach the new methods as properties to trackEvent
208208
const trackEventWithMethods = trackEvent;
209+
// eslint-disable-next-line react-compiler/react-compiler
209210
trackEventWithMethods.bufferedTrace = bufferedTrace;
210211
trackEventWithMethods.bufferedEndTrace = bufferedEndTrace;
211212
trackEventWithMethods.onboardingParentContext = onboardingParentContext;

ui/hooks/useAsync.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ export function useAsyncCallback<T>(
115115
setResult(createErrorResult(error as Error));
116116
}
117117
}
118+
// eslint-disable-next-line react-compiler/react-compiler
118119
}, deps);
119120

120121
return [execute, result];

0 commit comments

Comments
 (0)