Skip to content

Commit

Permalink
fix: enhance performance by muting unnecessary state subscription in …
Browse files Browse the repository at this point in the history
…UI (#514)

* chore: fix ui redux state over subscribe

* fix: lint

* chore: add missing redux state separation

---------

Co-authored-by: khanti42 <[email protected]>
  • Loading branch information
stanleyyconsensys and khanti42 authored Feb 25, 2025
1 parent 02ade89 commit e7c0f28
Show file tree
Hide file tree
Showing 13 changed files with 89 additions and 72 deletions.
8 changes: 4 additions & 4 deletions packages/wallet-ui/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,10 @@ library.add(fas, far);
function App() {
const { initSnap, initWalletData, checkConnection, loadLocale } =
useStarkNetSnap();
const { connected, forceReconnect, provider } = useAppSelector(
(state) => state.wallet,
);
const connected = useAppSelector((state) => state.wallet.connected);
const forceReconnect = useAppSelector((state) => state.wallet.forceReconnect);
const provider = useAppSelector((state) => state.wallet.provider);
const currentAccount = useAppSelector((state) => state.wallet.currentAccount);
const {
infoModalVisible,
minVersionModalVisible,
Expand All @@ -39,7 +40,6 @@ function App() {
} = useAppSelector((state) => state.modals);
const { loader } = useAppSelector((state) => state.UI);
const networks = useAppSelector((state) => state.networks);
const { currentAccount } = useAppSelector((state) => state.wallet);
const { hasMetamask } = useHasMetamask();
const chainId = networks.items?.[networks.activeNetwork]?.chainId;
const address = currentAccount.address;
Expand Down
8 changes: 4 additions & 4 deletions packages/wallet-ui/src/components/pages/Home/Home.view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ import { useAppSelector } from 'hooks/redux';
import { useMultiLanguage } from 'services';

export const HomeView = () => {
const { erc20TokenBalanceSelected, transactions } = useAppSelector(
(state) => state.wallet,
const erc20TokenBalanceSelected = useAppSelector(
(state) => state.wallet.erc20TokenBalanceSelected,
);
const transactions = useAppSelector((state) => state.wallet.transactions);
const { address } = useAppSelector((state) => state.wallet.currentAccount);
const loader = useAppSelector((state) => state.UI.loader);
const currentAccount = useAppSelector((state) => state.wallet.currentAccount);
const address = currentAccount.address;
const { upgradeModalVisible } = useAppSelector((state) => state.modals);
const { translate } = useMultiLanguage();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,16 @@ import { ASSETS_PRICE_REFRESH_FREQUENCY } from 'utils/constants';

export const AssetsListView = () => {
const { setErc20TokenBalance, refreshTokensUSDPrice } = useStarkNetSnap();
const wallet = useAppSelector((state) => state.wallet);
const erc20TokenBalances = useAppSelector(
(state) => state.wallet.erc20TokenBalances,
);
const erc20TokenBalanceSelected = useAppSelector(
(state) => state.wallet.erc20TokenBalanceSelected,
);
const timeoutHandle = useRef(setTimeout(() => {}));

useEffect(() => {
if (wallet.erc20TokenBalances?.length > 0) {
if (erc20TokenBalances?.length > 0) {
clearTimeout(timeoutHandle.current); // cancel the timeout that was in-flight
timeoutHandle.current = setTimeout(
() => refreshTokensUSDPrice(),
Expand All @@ -22,20 +27,20 @@ export const AssetsListView = () => {
return () => clearTimeout(timeoutHandle.current);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [wallet.erc20TokenBalances]);
}, [erc20TokenBalances]);

const handleClick = (asset: Erc20TokenBalance) => {
setErc20TokenBalance(asset);
};

return (
<Wrapper<FC<IListProps<Erc20TokenBalance>>>
data={wallet.erc20TokenBalances}
data={erc20TokenBalances}
render={(asset) => (
<AssetListItem
asset={asset}
onClick={() => handleClick(asset)}
selected={wallet.erc20TokenBalanceSelected.address === asset.address}
selected={erc20TokenBalanceSelected.address === asset.address}
/>
)}
keyExtractor={(asset) => asset.address}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,23 @@ interface Props {
}

export const TransactionListItemView = ({ transaction }: Props) => {
const wallet = useAppSelector((state) => state.wallet);
const tokenAddress = wallet.erc20TokenBalanceSelected.address;
const { translate } = useMultiLanguage();
const erc20TokenBalances = useAppSelector(
(state) => state.wallet.erc20TokenBalances,
);
const erc20TokenBalanceSelected = useAppSelector(
(state) => state.wallet.erc20TokenBalanceSelected,
);
const locale = useAppSelector((state) => state.wallet.locale);
const [currencySymbol, setCurrencySymbol] = useState('N/A');
const [txnValue, setTxnValue] = useState('0');
const [txnUsdValue, setTxnUsdValue] = useState('0.00');
const { translate } = useMultiLanguage();

const { locale } = useAppSelector((state) => state.wallet);
const tokenAddress = erc20TokenBalanceSelected.address;

useEffect(() => {
const fetchData = async () => {
// Find the matching token
const foundToken = wallet.erc20TokenBalances.find((token) =>
const foundToken = erc20TokenBalances.find((token) =>
ethers.BigNumber.from(token.address).eq(
ethers.BigNumber.from(tokenAddress),
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ interface Props {

export const AccountSwitchModalView = ({ full, starkName }: Props) => {
const networks = useAppSelector((state) => state.networks);
const { currentAccount, accounts } = useAppSelector((state) => state.wallet);
const currentAccount = useAppSelector((state) => state.wallet.currentAccount);
const accounts = useAppSelector((state) => state.wallet.accounts);
const { switchAccount, hideAccount, unHideAccount } = useStarkNetSnap();
const { translate } = useMultiLanguage();
const chainId = networks?.items[networks.activeNetwork]?.chainId;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export const AddTokenModalView = ({ closeModal }: Props) => {
const { translate } = useMultiLanguage();
const [enabled, setEnabled] = useState(false);
const networks = useAppSelector((state) => state.networks);
const { currentAccount } = useAppSelector((state) => state.wallet);
const currentAccount = useAppSelector((state) => state.wallet.currentAccount);
const chainId = networks?.items[networks.activeNetwork].chainId;
const [isValidAddress, setIsValidAddress] = useState(false);
const [fields, setFields] = useState({
Expand All @@ -36,6 +36,7 @@ export const AddTokenModalView = ({ closeModal }: Props) => {
symbol: '',
decimal: '',
});

const handleChange = (fieldName: string, fieldValue: string) => {
setFields((prevFields) => ({
...prevFields,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,27 +17,25 @@ interface Props {
}

export const HeaderView = ({ address }: Props) => {
const { updateTokenBalance } = useStarkNetSnap();
const { translate } = useMultiLanguage();
const [receiveOpen, setReceiveOpen] = useState(false);
const [sendOpen, setSendOpen] = useState(false);
const networks = useAppSelector((state) => state.networks);
const wallet = useAppSelector((state) => state.wallet);
const { updateTokenBalance } = useStarkNetSnap();
const { translate } = useMultiLanguage();
const erc20TokenBalanceSelected = useAppSelector(
(state) => state.wallet.erc20TokenBalanceSelected,
);
const timeoutHandle = useRef(setTimeout(() => {}));

const getUSDValue = () => {
const amountFloat = parseFloat(
ethers.utils.formatUnits(
wallet.erc20TokenBalanceSelected.amount,
wallet.erc20TokenBalanceSelected.decimals,
erc20TokenBalanceSelected.amount,
erc20TokenBalanceSelected.decimals,
),
);
if (wallet.erc20TokenBalanceSelected.usdPrice)
return getAmountPrice(
wallet.erc20TokenBalanceSelected,
amountFloat,
false,
);
if (erc20TokenBalanceSelected.usdPrice)
return getAmountPrice(erc20TokenBalanceSelected, amountFloat, false);
return '';
};

Expand All @@ -47,15 +45,15 @@ export const HeaderView = ({ address }: Props) => {
clearTimeout(timeoutHandle.current); // cancel the timeout that was in-flight
timeoutHandle.current = setTimeout(async () => {
await updateTokenBalance(
wallet.erc20TokenBalanceSelected.address,
erc20TokenBalanceSelected.address,
address,
chain,
);
}, TOKEN_BALANCE_REFRESH_FREQUENCY);
return () => clearTimeout(timeoutHandle.current);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [wallet.erc20TokenBalanceSelected]);
}, [erc20TokenBalanceSelected]);

const handleSendClick = () => {
setSendOpen(true);
Expand All @@ -65,10 +63,8 @@ export const HeaderView = ({ address }: Props) => {
<Wrapper>
<AssetQuantity
USDValue={getUSDValue()}
currencyValue={getSpendableTotalBalance(
wallet.erc20TokenBalanceSelected,
)}
currency={wallet.erc20TokenBalanceSelected.symbol}
currencyValue={getSpendableTotalBalance(erc20TokenBalanceSelected)}
currency={erc20TokenBalanceSelected.symbol}
size="big"
centered
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ interface Props {
export const SendModalView = ({ closeModal }: Props) => {
const networks = useAppSelector((state) => state.networks);
const chainId = networks?.items[networks.activeNetwork]?.chainId;
const wallet = useAppSelector((state) => state.wallet);
const erc20TokenBalanceSelected = useAppSelector(
(state) => state.wallet.erc20TokenBalanceSelected,
);
const { getAddrFromStarkName } = useStarkNetSnap();
const { translate } = useMultiLanguage();
const [summaryModalOpen, setSummaryModalOpen] = useState(false);
Expand Down Expand Up @@ -63,9 +65,9 @@ export const SendModalView = ({ closeModal }: Props) => {
if (fieldValue !== '' && fieldValue !== '.') {
const inputAmount = ethers.utils.parseUnits(
fieldValue,
wallet.erc20TokenBalanceSelected.decimals,
erc20TokenBalanceSelected.decimals,
);
const userBalance = wallet.erc20TokenBalanceSelected.amount;
const userBalance = erc20TokenBalanceSelected.amount;
if (inputAmount.gt(userBalance)) {
setErrors((prevErrors) => ({
...prevErrors,
Expand Down Expand Up @@ -166,8 +168,8 @@ export const SendModalView = ({ closeModal }: Props) => {
value={fields.amount}
error={errors.amount !== '' ? true : false}
helperText={errors.amount}
decimalsMax={wallet.erc20TokenBalanceSelected.decimals}
asset={wallet.erc20TokenBalanceSelected}
decimalsMax={erc20TokenBalanceSelected.decimals}
asset={erc20TokenBalanceSelected}
/>
<SeparatorSmall />
<div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,13 @@ export const SendSummaryModalView = ({
handleBack,
selectedFeeToken,
}: Props) => {
const wallet = useAppSelector((state) => state.wallet);
const currentAccount = wallet.currentAccount;
const currentAccount = useAppSelector((state) => state.wallet.currentAccount);
const erc20TokenBalances = useAppSelector(
(state) => state.wallet.erc20TokenBalances,
);
const erc20TokenBalanceSelected = useAppSelector(
(state) => state.wallet.erc20TokenBalanceSelected,
);
const [estimatingGas, setEstimatingGas] = useState(true);
const [gasFees, setGasFees] = useState({
suggestedMaxFee: '0',
Expand All @@ -70,11 +75,10 @@ export const SendSummaryModalView = ({
const { estimateFees, sendTransaction, getTransactions } = useStarkNetSnap();
const { translate } = useMultiLanguage();

const ethToken = wallet.erc20TokenBalances[0];
const ethToken = erc20TokenBalances[0];
const feeToken =
wallet.erc20TokenBalances.find(
(token) => token.symbol === selectedFeeToken,
) ?? ethToken;
erc20TokenBalances.find((token) => token.symbol === selectedFeeToken) ??
ethToken;

const toastr = new Toastr({
closeDuration: 10000000,
Expand All @@ -88,11 +92,11 @@ export const SendSummaryModalView = ({
setEstimatingGas(true);
const amountBN = ethers.utils.parseUnits(
amount,
wallet.erc20TokenBalanceSelected.decimals,
erc20TokenBalanceSelected.decimals,
);
const callData = address + ',' + amountBN.toString() + ',0';
estimateFees(
wallet.erc20TokenBalanceSelected.address,
erc20TokenBalanceSelected.address,
ContractFuncName.Transfer,
callData,
currentAccount.address,
Expand Down Expand Up @@ -128,11 +132,11 @@ export const SendSummaryModalView = ({
}
const amountBN = ethers.utils.parseUnits(
amount,
wallet.erc20TokenBalanceSelected.decimals,
erc20TokenBalanceSelected.decimals,
);
// Combine the transaction amount and fee amount if they are the same token.
// And verify if the combined amount is not exceeding the total balance.
if (wallet.erc20TokenBalanceSelected.address === feeToken.address) {
if (erc20TokenBalanceSelected.address === feeToken.address) {
const totalAmountBN = gasFeesBN.add(amountBN);
totalToCheck = totalAmountBN;
const totalAmount = ethers.utils.formatUnits(
Expand Down Expand Up @@ -165,20 +169,20 @@ export const SendSummaryModalView = ({

useEffect(() => {
const amountFloat = parseFloat(amount);
wallet.erc20TokenBalanceSelected.usdPrice &&
erc20TokenBalanceSelected.usdPrice &&
setAmountUsdPrice(
getAmountPrice(wallet.erc20TokenBalanceSelected, amountFloat, false),
getAmountPrice(erc20TokenBalanceSelected, amountFloat, false),
);
}, [amount, wallet.erc20TokenBalanceSelected]);
}, [amount, erc20TokenBalanceSelected]);

const handleConfirmClick = () => {
const amountBN = ethers.utils.parseUnits(
amount,
wallet.erc20TokenBalanceSelected.decimals,
erc20TokenBalanceSelected.decimals,
);
const callData = address + ',' + amountBN.toString() + ',0';
sendTransaction(
wallet.erc20TokenBalanceSelected.address,
erc20TokenBalanceSelected.address,
ContractFuncName.Transfer,
callData,
currentAccount.address,
Expand All @@ -191,7 +195,7 @@ export const SendSummaryModalView = ({
toastr.success(translate('transactionSentSuccessfully'));
getTransactions(
currentAccount.address,
wallet.erc20TokenBalanceSelected.address,
erc20TokenBalanceSelected.address,
10,
chainId,
false,
Expand All @@ -212,14 +216,14 @@ export const SendSummaryModalView = ({
};

const totalAmountDisplay = () => {
if (wallet.erc20TokenBalances.length > 0) {
if (wallet.erc20TokenBalanceSelected.address === feeToken.address) {
if (erc20TokenBalances.length > 0) {
if (erc20TokenBalanceSelected.address === feeToken.address) {
return totalAmount + ` ${feeToken.symbol}`;
} else {
return (
getHumanReadableAmount(wallet.erc20TokenBalanceSelected, amount) +
getHumanReadableAmount(erc20TokenBalanceSelected, amount) +
' ' +
wallet.erc20TokenBalanceSelected.symbol +
erc20TokenBalanceSelected.symbol +
' + ' +
gasFeesAmount +
` ${feeToken.symbol}`
Expand All @@ -237,9 +241,9 @@ export const SendSummaryModalView = ({
<ToDiv>To</ToDiv>
<AddressDiv>{shortenAddress(address)}</AddressDiv>
<AssetQuantity
currency={wallet.erc20TokenBalanceSelected.symbol}
currency={erc20TokenBalanceSelected.symbol}
currencyValue={getMaxDecimalsReadable(
wallet.erc20TokenBalanceSelected,
erc20TokenBalanceSelected,
amount,
)}
USDValue={amountUsdPrice}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,14 @@ import { PopperTooltip } from 'components/ui/molecule/PopperTooltip';
export const SideBarView = () => {
const networks = useAppSelector((state) => state.networks);
const currentAccount = useAppSelector((state) => state.wallet.currentAccount);
const erc20TokenBalances = useAppSelector(
(state) => state.wallet.erc20TokenBalances,
);
const connected = useAppSelector((state) => state.wallet.connected);
const chainId = networks?.items[networks.activeNetwork]?.chainId;
const [listOverflow, setListOverflow] = useState(false);
const [infoModalOpen, setInfoModalOpen] = useState(false);
const [accountDetailsOpen, setAccountDetailsOpen] = useState(false);
const wallet = useAppSelector((state) => state.wallet);
const [addTokenOpen, setAddTokenOpen] = useState(false);
const { getStarkName } = useStarkNetSnap();
const { translate } = useMultiLanguage();
Expand All @@ -51,7 +54,7 @@ export const SideBarView = () => {
setListOverflow(false);
}
}
}, [wallet.erc20TokenBalances]);
}, [erc20TokenBalances]);

useEffect(() => {
if (address && address !== defaultAccount.address) {
Expand Down Expand Up @@ -107,7 +110,7 @@ export const SideBarView = () => {
</AccountDetailsContent>
}
>
<AccountImageStyled address={address} connected={wallet.connected} />
<AccountImageStyled address={address} connected={connected} />
</AccountDetails>

<AccountLabel>{currentAccount.accountName}</AccountLabel>
Expand Down
Loading

0 comments on commit e7c0f28

Please sign in to comment.