diff --git a/package.json b/package.json index ecf974b9f0..6d3b65f555 100644 --- a/package.json +++ b/package.json @@ -8,10 +8,10 @@ "packages/*" ], "resolutions": { - "@polkadot/api": "^1.6.0-beta.28", - "@polkadot/api-contract": "^1.6.0-beta.28", + "@polkadot/api": "^1.6.1", + "@polkadot/api-contract": "^1.6.1", "@polkadot/keyring": "^2.6.2", - "@polkadot/types": "^1.6.0-beta.28", + "@polkadot/types": "^1.6.1", "@polkadot/util": "^2.6.2", "@polkadot/util-crypto": "^2.6.2", "babel-core": "^7.0.0-bridge.0", diff --git a/packages/page-accounts/src/modals/RecoverSetup.tsx b/packages/page-accounts/src/modals/RecoverSetup.tsx index 2b07d91ecc..518edbdfd7 100644 --- a/packages/page-accounts/src/modals/RecoverSetup.tsx +++ b/packages/page-accounts/src/modals/RecoverSetup.tsx @@ -27,11 +27,9 @@ export default function RecoverSetup ({ address, className, onClose }: Props): R const [threshold, setThreshold] = useState(); useEffect((): void => { - if (allAccounts && allAddresses) { - setAvailableHelpers( - [...allAccounts, ...allAddresses].filter((a): boolean => a !== address) - ); - } + allAccounts && allAddresses && setAvailableHelpers( + [...allAccounts, ...allAddresses].filter((a): boolean => a !== address) + ); }, [address, allAccounts, allAddresses]); const isErrorDelay = !delay; diff --git a/packages/page-accounts/src/modals/Transfer.tsx b/packages/page-accounts/src/modals/Transfer.tsx index 01f1cee605..fea3cdfa64 100644 --- a/packages/page-accounts/src/modals/Transfer.tsx +++ b/packages/page-accounts/src/modals/Transfer.tsx @@ -71,14 +71,12 @@ function Transfer ({ className, onClose, recipientId: propRecipientId, senderId: const [senderId, setSenderId] = useState(propSenderId || null); useEffect((): void => { - if (senderId && recipientId) { - setExtrinsic(api.tx.balances.transfer(recipientId, amount || ZERO)); + senderId && recipientId && setExtrinsic(api.tx.balances.transfer(recipientId, amount || ZERO)); - // We currently have not enabled the max functionality - we don't take care of weights - // calcMax(api, balances_fees, senderId, recipientId) - // .then(([maxBalance]): void => setMaxBalance(maxBalance)) - // .catch((error: Error): void => console.error(error)); - } + // We currently have not enabled the max functionality - we don't take care of weights + // calcMax(api, balances_fees, senderId, recipientId) + // .then(([maxBalance]): void => setMaxBalance(maxBalance)) + // .catch((error: Error): void => console.error(error)); }, [amount, recipientId, senderId]); const transferrable = {t('transferrable')}; diff --git a/packages/page-contracts/package.json b/packages/page-contracts/package.json index 16f8159098..eed2ecef1a 100644 --- a/packages/page-contracts/package.json +++ b/packages/page-contracts/package.json @@ -12,6 +12,6 @@ "license": "Apache-2.0", "dependencies": { "@babel/runtime": "^7.8.7", - "@polkadot/api-contract": "^1.6.0-beta.28" + "@polkadot/api-contract": "^1.6.1" } } diff --git a/packages/page-contracts/src/Params.tsx b/packages/page-contracts/src/Params.tsx index 4a63ed8c32..ecc34b694c 100644 --- a/packages/page-contracts/src/Params.tsx +++ b/packages/page-contracts/src/Params.tsx @@ -25,9 +25,7 @@ export default function Params ({ isDisabled, onChange, onEnter, params: propPar const [params, setParams] = useState([]); useEffect((): void => { - if (propParams) { - setParams(propParams); - } + propParams && setParams(propParams); }, [propParams]); if (!params.length) { diff --git a/packages/page-democracy/src/Overview/DispatchBlock.tsx b/packages/page-democracy/src/Overview/DispatchBlock.tsx index 5abc1ab835..dc3705f37c 100644 --- a/packages/page-democracy/src/Overview/DispatchBlock.tsx +++ b/packages/page-democracy/src/Overview/DispatchBlock.tsx @@ -29,11 +29,11 @@ export default function DispatchBlock ({ entries, keyPrefix, storageKey }: Props const [expanded, setExpanded] = useState([]); useEffect((): void => { - if (keyPrefix && storageKey) { - setBlockNumber(createType(registry, 'BlockNumber', hexToU8a( + keyPrefix && storageKey && setBlockNumber( + createType(registry, 'BlockNumber', hexToU8a( `0x${storageKey.toHex().replace(keyPrefix, '').substr(16)}`) - )); - } + ) + ); }, [keyPrefix, storageKey]); useEffect((): void => { diff --git a/packages/page-democracy/src/Overview/DispatchEntry.tsx b/packages/page-democracy/src/Overview/DispatchEntry.tsx index 4ee6d7acf4..51d1fb0e7d 100644 --- a/packages/page-democracy/src/Overview/DispatchEntry.tsx +++ b/packages/page-democracy/src/Overview/DispatchEntry.tsx @@ -32,9 +32,7 @@ export default function DispatchEntry ({ blockNumber, hash, referendumIndex }: P const [proposal, setProposal] = useState(); useEffect((): void => { - if (preimage?.isSome) { - setProposal(api.createType('Proposal', preimage.unwrap()[0].toU8a(true))); - } + preimage?.isSome && setProposal(api.createType('Proposal', preimage.unwrap()[0].toU8a(true))); }, [preimage]); return ( diff --git a/packages/page-explorer/src/NodeInfo/Summary.tsx b/packages/page-explorer/src/NodeInfo/Summary.tsx index d6ebb541f6..ae06f87112 100644 --- a/packages/page-explorer/src/NodeInfo/Summary.tsx +++ b/packages/page-explorer/src/NodeInfo/Summary.tsx @@ -25,17 +25,15 @@ function Summary ({ info: { extrinsics, health, peers } = EMPTY_INFO, nextRefres const [peerBest, setPeerBest] = useState(ZERO); useEffect((): void => { - if (!peers) { - return; + if (peers) { + const bestPeer = peers.sort((a, b): number => b.bestNumber.cmp(a.bestNumber))[0]; + + setPeerBest( + bestPeer + ? bestPeer.bestNumber + : new BN(0) + ); } - - const bestPeer = peers.sort((a, b): number => b.bestNumber.cmp(a.bestNumber))[0]; - - setPeerBest( - bestPeer - ? bestPeer.bestNumber - : new BN(0) - ); }, [peers]); return ( diff --git a/packages/page-settings/src/SelectUrl.tsx b/packages/page-settings/src/SelectUrl.tsx index 0b2c50dbf5..b1393a581f 100644 --- a/packages/page-settings/src/SelectUrl.tsx +++ b/packages/page-settings/src/SelectUrl.tsx @@ -68,9 +68,7 @@ function SelectUrl ({ className, onChange }: Props): React.ReactElement { }, [t]); useEffect((): void => { - if (onChange && info.isValid) { - onChange(info.url); - } + onChange && info.isValid && onChange(info.url); }, [info]); const _onChangeUrl = (url: string): void => setInfo({ ...info, ...makeUrl(url) }); diff --git a/packages/page-society/src/Overview/VoteDisplay.tsx b/packages/page-society/src/Overview/VoteDisplay.tsx index 9fef982fd2..6e54a54f04 100644 --- a/packages/page-society/src/Overview/VoteDisplay.tsx +++ b/packages/page-society/src/Overview/VoteDisplay.tsx @@ -18,13 +18,11 @@ export default function VoteDisplay ({ votes }: Props): React.ReactElement({ allAye: [], allNay: [], allSkeptic: [] }); useEffect((): void => { - if (votes) { - setVoteSplit({ - allAye: votes.filter(([, vote]): boolean => vote.isApprove), - allNay: votes.filter(([, vote]): boolean => vote.isReject), - allSkeptic: votes.filter(([, vote]): boolean => vote.isSkeptic) - }); - } + votes && setVoteSplit({ + allAye: votes.filter(([, vote]): boolean => vote.isApprove), + allNay: votes.filter(([, vote]): boolean => vote.isReject), + allSkeptic: votes.filter(([, vote]): boolean => vote.isSkeptic) + }); }, [votes]); return ( diff --git a/packages/page-staking/src/Actions/Account/Nominate.tsx b/packages/page-staking/src/Actions/Account/Nominate.tsx index c20390365f..4f6c2045a4 100644 --- a/packages/page-staking/src/Actions/Account/Nominate.tsx +++ b/packages/page-staking/src/Actions/Account/Nominate.tsx @@ -32,15 +32,13 @@ function Nominate ({ className, controllerId, nominees, onClose, next, stakingOv const [available, setAvailable] = useState([]); useEffect((): void => { - if (!selection && nominees) { - setSelection(nominees); - } + !selection && nominees && setSelection(nominees); }, [selection, nominees]); useEffect((): void => { - if (stakingOverview) { - setValidators(stakingOverview.validators.map((acc): string => acc.toString())); - } + stakingOverview && setValidators( + stakingOverview.validators.map((acc): string => acc.toString()) + ); }, [stakingOverview]); useEffect((): void => { diff --git a/packages/page-staking/src/Actions/Account/index.tsx b/packages/page-staking/src/Actions/Account/index.tsx index 5659f1f405..c7839ea9b9 100644 --- a/packages/page-staking/src/Actions/Account/index.tsx +++ b/packages/page-staking/src/Actions/Account/index.tsx @@ -3,7 +3,7 @@ // of the Apache-2.0 license. See the LICENSE file for details. import { SubmittableExtrinsic } from '@polkadot/api/types'; -import { DerivedBalancesAll, DerivedStakingAccount, DerivedStakingOverview, DeriveStakerReward, DerivedHeartbeats } from '@polkadot/api-derive/types'; +import { DerivedBalancesAll, DerivedStakingAccount, DerivedStakingOverview, DeriveStakerReward } from '@polkadot/api-derive/types'; import { AccountId, EraIndex, Exposure, StakingLedger, ValidatorPrefs } from '@polkadot/types/interfaces'; import { Codec, ITuple } from '@polkadot/types/types'; @@ -39,7 +39,6 @@ interface Props { isVisible: boolean; next?: string[]; onUpdateType: (stashId: string, type: 'validator' | 'nominator' | 'started' | 'other') => void; - recentlyOnline?: DerivedHeartbeats; rewards?: DeriveStakerReward[]; stakingOverview?: DerivedStakingOverview; stashId: string; @@ -474,7 +473,7 @@ function Account ({ allStashes, className, isOwnStash, next, onUpdateType, rewar ); } -export default styled(Account)` +export default React.memo(styled(Account)` .ui--Button-Group { display: inline-block; margin-right: 0.25rem; @@ -484,4 +483,4 @@ export default styled(Account)` .mini-nopad { padding: 0; } -`; +`); diff --git a/packages/page-staking/src/Actions/index.tsx b/packages/page-staking/src/Actions/index.tsx index 836769864f..6fa0df12bf 100644 --- a/packages/page-staking/src/Actions/index.tsx +++ b/packages/page-staking/src/Actions/index.tsx @@ -2,7 +2,7 @@ // This software may be modified and distributed under the terms // of the Apache-2.0 license. See the LICENSE file for details. -import { DerivedHeartbeats, DerivedStakingOverview, DeriveStakerReward } from '@polkadot/api-derive/types'; +import { DerivedStakingOverview, DeriveStakerReward } from '@polkadot/api-derive/types'; import { ActiveEraInfo, EraIndex } from '@polkadot/types/interfaces'; import React, { useEffect, useState } from 'react'; @@ -19,12 +19,11 @@ interface Props { allStashes?: string[]; className?: string; isVisible: boolean; - recentlyOnline?: DerivedHeartbeats; next?: string[]; stakingOverview?: DerivedStakingOverview; } -export default function Actions ({ allRewards, allStashes, className, isVisible, next, recentlyOnline, stakingOverview }: Props): React.ReactElement { +export default function Actions ({ allRewards, allStashes, className, isVisible, next, stakingOverview }: Props): React.ReactElement { const { t } = useTranslation(); const { api } = useApi(); const activeEra = useCall(api.query.staking?.activeEra, [], { @@ -84,7 +83,6 @@ export default function Actions ({ allRewards, allStashes, className, isVisible, key={stashId} next={next} onUpdateType={_onUpdateType} - recentlyOnline={recentlyOnline} rewards={allRewards && allRewards[stashId]} stakingOverview={stakingOverview} stashId={stashId} diff --git a/packages/page-staking/src/Overview/Address.tsx b/packages/page-staking/src/Overview/Address.tsx index 7d2a960459..f779fcf7fe 100644 --- a/packages/page-staking/src/Overview/Address.tsx +++ b/packages/page-staking/src/Overview/Address.tsx @@ -98,7 +98,7 @@ function checkVisibility (api: ApiPromise, address: string, filterName: string, return isVisible; } -export default function Address ({ address, className, filterName, hasQueries, heartbeat, isAuthor, isElected, isFavorite, isMain, lastBlock, myAccounts, points, setNominators, toggleFavorite, withNominations }: Props): React.ReactElement | null { +function Address ({ address, className, filterName, hasQueries, heartbeat, isAuthor, isElected, isFavorite, isMain, lastBlock, myAccounts, points, setNominators, toggleFavorite, withNominations }: Props): React.ReactElement | null { const { t } = useTranslation(); const { api } = useApi(); const info = useCall(api.derive.accounts.info as any, [address]); @@ -233,3 +233,5 @@ export default function Address ({ address, className, filterName, hasQueries, h ); } + +export default React.memo(Address); diff --git a/packages/page-staking/src/Query/Validator.tsx b/packages/page-staking/src/Query/Validator.tsx index 6179ccb2e4..138e480fcb 100644 --- a/packages/page-staking/src/Query/Validator.tsx +++ b/packages/page-staking/src/Query/Validator.tsx @@ -40,6 +40,7 @@ interface ChartInfo { const COLORS_REWARD = ['#8c2200', '#008c22', '#acacac']; const COLORS_POINTS = [undefined, '#acacac']; +const COLORS_STAKE = COLORS_POINTS; function balanceToNumber (amount: BN, divisor: BN): number { return amount.muln(1000).div(divisor).toNumber() / 1000; @@ -49,13 +50,18 @@ function extractPoints (points: DeriveStakerPoints[]): ChartInfo { const labels: string[] = []; const avgSet: LineDataEntry = []; const idxSet: LineDataEntry = []; + let avgCount = 0; let total = 0; - points.forEach(({ era, points }, index): void => { + points.forEach(({ era, points }): void => { total += points.toNumber(); labels.push(era.toHuman()); - avgSet.push(Math.ceil(total * 100 / (index + 1)) / 100); + if (total > 0) { + avgCount++; + } + + avgSet.push((avgCount ? Math.ceil(total * 100 / avgCount) : 0) / 100); idxSet.push(points); }); @@ -70,19 +76,24 @@ function extractRewards (erasRewards: DeriveEraRewards[], allPoints: DeriveStake const slashSet: LineDataEntry = []; const rewardSet: LineDataEntry = []; const avgSet: LineDataEntry = []; + let avgCount = 0; let total = 0; - erasRewards.forEach(({ era, eraReward }, index): void => { + erasRewards.forEach(({ era, eraReward }): void => { const points = allPoints.find((points) => points.era.eq(era)); const reward = points?.eraPoints.gtn(0) ? balanceToNumber(points.points.mul(eraReward).div(points.eraPoints), divisor) : 0; total += reward; - labels.push(era.toHuman()); + if (total > 0) { + avgCount++; + } + + labels.push(era.toHuman()); rewardSet.push(reward); - avgSet.push(Math.ceil(total * 100 / (index + 1)) / 100); + avgSet.push((avgCount ? Math.ceil(total * 100 / avgCount) : 0) / 100); slashSet.push(0); // TODO }); @@ -95,21 +106,31 @@ function extractRewards (erasRewards: DeriveEraRewards[], allPoints: DeriveStake function extractStake (exposures: DeriveStakerExposure[], divisor: BN): ChartInfo { const labels: string[] = []; const stakeSet: LineDataEntry = []; + const avgSet: LineDataEntry = []; + let avgCount = 0; + let total = 0; exposures.forEach(({ era, isValidator, validators }): void => { - labels.push(era.toHuman()); - stakeSet.push( - balanceToNumber( - isValidator - ? Object.values(validators)[0].total.toBn() - : new BN(0), - divisor - ) + const value = balanceToNumber( + isValidator + ? Object.values(validators)[0].total.toBn() + : new BN(0), + divisor ); + + total += value; + + if (total > 0) { + avgCount++; + } + + avgSet.push((avgCount ? Math.ceil(total * 100 / avgCount) : 0) / 100); + labels.push(era.toHuman()); + stakeSet.push(value); }); return { - chart: [stakeSet], + chart: [stakeSet, avgSet], labels }; } @@ -129,15 +150,21 @@ export default function Validator ({ className, validatorId }: Props): React.Rea }), [formatBalance]); useEffect((): void => { - stakerPoints && setPointChart(extractPoints(stakerPoints)); + stakerPoints && setPointChart( + extractPoints(stakerPoints) + ); }, [stakerPoints]); useEffect((): void => { - erasRewards && stakerPoints && setRewardChart(extractRewards(erasRewards, stakerPoints, divisor)); + erasRewards && stakerPoints && setRewardChart( + extractRewards(erasRewards, stakerPoints, divisor) + ); }, [erasRewards, stakerPoints]); useEffect((): void => { - stakerExposure && setStakeCharts(extractStake(stakerExposure, divisor)); + stakerExposure && setStakeCharts( + extractStake(stakerExposure, divisor) + ); }, [stakerExposure]); return ( @@ -178,8 +205,9 @@ export default function Validator ({ className, validatorId }: Props): React.Rea {stakeChart && !!stakeChart[0]?.length ? ( ) diff --git a/packages/page-staking/src/Targets/Summary.tsx b/packages/page-staking/src/Targets/Summary.tsx index f5f98960cb..bd85b1c650 100644 --- a/packages/page-staking/src/Targets/Summary.tsx +++ b/packages/page-staking/src/Targets/Summary.tsx @@ -30,11 +30,9 @@ export default function Summary ({ lastReward, numNominators, numValidators, tot const [{ percentage }, setStakeInfo] = useState({}); useEffect((): void => { - if (totalInsurance && totalStaked?.gtn(0)) { - setStakeInfo({ - percentage: `${(totalStaked.muln(10000).div(totalInsurance).toNumber() / 100).toFixed(2)}%` - }); - } + totalInsurance && totalStaked?.gtn(0) && setStakeInfo({ + percentage: `${(totalStaked.muln(10000).div(totalInsurance).toNumber() / 100).toFixed(2)}%` + }); }, [totalInsurance, totalStaked]); return ( diff --git a/packages/page-staking/src/Targets/Validator.tsx b/packages/page-staking/src/Targets/Validator.tsx index d5a4eb51f7..d22ea07285 100644 --- a/packages/page-staking/src/Targets/Validator.tsx +++ b/packages/page-staking/src/Targets/Validator.tsx @@ -16,7 +16,7 @@ interface Props { toggleFavorite: (accountId: string) => void; } -export default function Validator ({ info: { accountId, bondOther, bondOwn, bondTotal, commissionPer, isCommission, isFavorite, isNominating, key, numNominators, rankOverall, rewardPayout, validatorPayment }, toggleFavorite }: Props): React.ReactElement { +function Validator ({ info: { accountId, bondOther, bondOwn, bondTotal, commissionPer, isCommission, isFavorite, isNominating, key, numNominators, rankOverall, rewardPayout, validatorPayment }, toggleFavorite }: Props): React.ReactElement { const { t } = useTranslation(); const _onFavorite = (): void => toggleFavorite(key); const _onQueryStats = (): void => { @@ -57,3 +57,5 @@ export default function Validator ({ info: { accountId, bondOther, bondOwn, bond ); } + +export default React.memo(Validator); diff --git a/packages/page-staking/src/index.tsx b/packages/page-staking/src/index.tsx index 261b7446ad..604795f6e1 100644 --- a/packages/page-staking/src/index.tsx +++ b/packages/page-staking/src/index.tsx @@ -121,7 +121,6 @@ function StakingApp ({ basePath, className }: Props): React.ReactElement allRewards={allRewards} allStashes={allStashes} isVisible={pathname === `${basePath}/actions`} - recentlyOnline={recentlyOnline} next={next} stakingOverview={stakingOverview} /> diff --git a/packages/page-sudo/src/SetKey.tsx b/packages/page-sudo/src/SetKey.tsx index 72e0cf82eb..5ce2d96587 100644 --- a/packages/page-sudo/src/SetKey.tsx +++ b/packages/page-sudo/src/SetKey.tsx @@ -18,9 +18,7 @@ function SetKey ({ allAccounts, className, isMine, sudoKey }: Props): React.Reac const [selected, setSelected] = useState(null); useEffect((): void => { - if (sudoKey && !selected) { - setSelected(sudoKey); - } + sudoKey && !selected && setSelected(sudoKey); }, [selected, sudoKey]); const willLose = isMine && diff --git a/packages/page-treasury/src/Overview/Proposals.tsx b/packages/page-treasury/src/Overview/Proposals.tsx index 856d77d52c..5512e87831 100644 --- a/packages/page-treasury/src/Overview/Proposals.tsx +++ b/packages/page-treasury/src/Overview/Proposals.tsx @@ -28,13 +28,11 @@ export default function ProposalsBase ({ className, isApprovals, proposals }: Pr const history = useHistory(); useEffect((): void => { - if (allAccounts && members) { - setIsMember( - members - .map(([accountId]): string => accountId.toString()) - .some((accountId): boolean => allAccounts.includes(accountId)) - ); - } + allAccounts && members && setIsMember( + members + .map(([accountId]): string => accountId.toString()) + .some((accountId): boolean => allAccounts.includes(accountId)) + ); }, [allAccounts, members]); const _onRespond = (): void => { diff --git a/packages/react-api/package.json b/packages/react-api/package.json index 00fa262498..a04fde2267 100644 --- a/packages/react-api/package.json +++ b/packages/react-api/package.json @@ -31,7 +31,7 @@ "homepage": "https://github.com/polkadot-js/ui/tree/master/packages/ui-reactive#readme", "dependencies": { "@babel/runtime": "^7.8.7", - "@polkadot/api": "^1.6.0-beta.28", + "@polkadot/api": "^1.6.1", "@polkadot/extension-dapp": "^0.22.1", "rxjs-compat": "^6.5.4" } diff --git a/packages/react-components/src/AccountName.tsx b/packages/react-components/src/AccountName.tsx index 3d21b22b8c..70535fc366 100644 --- a/packages/react-components/src/AccountName.tsx +++ b/packages/react-components/src/AccountName.tsx @@ -103,17 +103,15 @@ function AccountName ({ children, className, defaultName, label, onClick, overri // determine if we have a registrar or not - registrars are allowed to approve useEffect((): void => { - if (allAccounts && registrars) { - setIsRegistrar( - registrars - .map((registrar): string| null => - registrar.isSome - ? registrar.unwrap().account.toString() - : null - ) - .some((regId): boolean => !!regId && allAccounts.includes(regId)) - ); - } + allAccounts && registrars && setIsRegistrar( + registrars + .map((registrar): string| null => + registrar.isSome + ? registrar.unwrap().account.toString() + : null + ) + .some((regId): boolean => !!regId && allAccounts.includes(regId)) + ); }, [allAccounts, registrars]); // set the actual nickname, local name, accountIndex, accountId @@ -236,7 +234,7 @@ function AccountName ({ children, className, defaultName, label, onClick, overri ); } -export default styled(AccountName)` +export default React.memo(styled(AccountName)` .via-identity { display: inline-block; overflow: hidden; @@ -279,4 +277,4 @@ export default styled(AccountName)` margin-top: -2px; } } -`; +`); diff --git a/packages/react-components/src/AddressMini.tsx b/packages/react-components/src/AddressMini.tsx index 57473e511c..99a382f35a 100644 --- a/packages/react-components/src/AddressMini.tsx +++ b/packages/react-components/src/AddressMini.tsx @@ -92,7 +92,7 @@ function AddressMini ({ balance, bonded, children, className, iconInfo, isPadded ); } -export default styled(AddressMini)` +export default React.memo(styled(AddressMini)` display: inline-block; padding: 0 0.25rem 0 1rem; text-align: left; @@ -166,4 +166,4 @@ export default styled(AddressMini)` position: relative; vertical-align: middle; } -`; +`); diff --git a/packages/react-components/src/AddressSmall.tsx b/packages/react-components/src/AddressSmall.tsx index a5fda2d4dd..02cda4946d 100644 --- a/packages/react-components/src/AddressSmall.tsx +++ b/packages/react-components/src/AddressSmall.tsx @@ -40,7 +40,7 @@ function AddressSmall ({ className, defaultName, onClickName, overrideName, togg ); } -export default styled(AddressSmall)` +export default React.memo(styled(AddressSmall)` vertical-align: middle; white-space: nowrap; @@ -65,4 +65,4 @@ export default styled(AddressSmall)` text-overflow: ellipsis; } } -`; +`); diff --git a/packages/react-components/src/Badge.tsx b/packages/react-components/src/Badge.tsx index 79c0d88b01..92fcb05748 100644 --- a/packages/react-components/src/Badge.tsx +++ b/packages/react-components/src/Badge.tsx @@ -48,7 +48,7 @@ function Badge ({ className, hover, info, isGray, isInline, isSmall, isTooltip, ); } -export default styled(Badge)` +export default React.memo(styled(Badge)` border-radius: 16px; box-shadow: 0 3px 3px rgba(0, 0, 0, 0.2); color: #eee; @@ -150,4 +150,4 @@ export default styled(Badge)` width: auto; } } -`; +`); diff --git a/packages/react-components/src/IdentityIcon.tsx b/packages/react-components/src/IdentityIcon.tsx index dd007a59a1..e77bccd7f4 100644 --- a/packages/react-components/src/IdentityIcon.tsx +++ b/packages/react-components/src/IdentityIcon.tsx @@ -19,10 +19,10 @@ export function getIdentityTheme (systemName: string): 'empty' { return ((uiSettings.icon === 'default' && identityNodes[systemName.toLowerCase().replace(/-/g, ' ')]) || uiSettings.icon) as 'empty'; } -export default function IdentityIcon ({ className, onCopy, prefix, size, style, theme, value }: Props): React.ReactElement { +function IdentityIcon ({ className, onCopy, prefix, size, style, theme, value }: Props): React.ReactElement { const { api, isApiReady, systemName } = useApi(); const { t } = useTranslation(); - const info = useCall(isApiReady ? api.derive.accounts.info as any : undefined, [value]); + const info = useCall(isApiReady && api.derive.accounts.info as any, [value]); const { queueAction } = useContext(StatusContext); const validators = useContext(ValidatorsContext); const [isValidator, setIsValidator] = useState(false); @@ -30,15 +30,11 @@ export default function IdentityIcon ({ className, onCopy, prefix, size, style, const thisTheme = theme || getIdentityTheme(systemName); useEffect((): void => { - if (value) { - setIsValidator(validators.includes(value.toString())); - } + value && setIsValidator(validators.includes(value.toString())); }, [value, validators]); useEffect((): void => { - if (info) { - setAddress(info.accountId?.toString()); - } + info && setAddress(info.accountId?.toString()); }, [info]); const _onCopy = (account: string): void => { @@ -64,3 +60,5 @@ export default function IdentityIcon ({ className, onCopy, prefix, size, style, /> ); } + +export default React.memo(IdentityIcon); diff --git a/packages/react-components/src/InputNumber.tsx b/packages/react-components/src/InputNumber.tsx index 0f0b0c049c..9d067dfc34 100644 --- a/packages/react-components/src/InputNumber.tsx +++ b/packages/react-components/src/InputNumber.tsx @@ -205,9 +205,7 @@ export default function InputNumber (props: Props): React.ReactElement { ); useEffect((): void => { - if (propsValue && isNewPropsValue(propsValue, value, valueBn)) { - setValues(getValues(propsValue, si, props)); - } + propsValue && isNewPropsValue(propsValue, value, valueBn) && setValues(getValues(propsValue, si, props)); }, [propsValue]); useEffect((): void => { diff --git a/packages/react-components/src/Tooltip.tsx b/packages/react-components/src/Tooltip.tsx index e3fea02c80..99a29aba66 100644 --- a/packages/react-components/src/Tooltip.tsx +++ b/packages/react-components/src/Tooltip.tsx @@ -29,7 +29,7 @@ interface Props extends BareProps { trigger: string; } -function Tooltip ({ className, effect = 'solid', offset, place = 'bottom', text, trigger }: Props): React.ReactElement | null { +function Tooltip ({ className, effect = 'solid', offset, place = 'top', text, trigger }: Props): React.ReactElement | null { const defaultTooltipContainer = typeof document === 'undefined' ? {} as HTMLElement // This hack is required for server side renreding : document.createElement('div'); @@ -62,7 +62,7 @@ function Tooltip ({ className, effect = 'solid', offset, place = 'bottom', text, ); } -export default styled(Tooltip)` +export default React.memo(styled(Tooltip)` table { border: 0; @@ -87,4 +87,4 @@ export default styled(Tooltip)` opacity: 0.75 !important; font-size: 0.75em !important; } -`; +`); diff --git a/packages/react-hooks/package.json b/packages/react-hooks/package.json index aaae0ea8cc..0a67c74ab8 100644 --- a/packages/react-hooks/package.json +++ b/packages/react-hooks/package.json @@ -30,6 +30,10 @@ }, "homepage": "https://github.com/polkadot-js/ui/tree/master/packages/ui-reactive#readme", "dependencies": { - "@babel/runtime": "^7.8.7" + "@babel/runtime": "^7.8.7", + "memoizee": "^0.4.14" + }, + "devDependencies": { + "@types/memoizee": "^0.4.3" } } diff --git a/packages/react-hooks/src/memo.ts b/packages/react-hooks/src/memo.ts new file mode 100644 index 0000000000..886f30d40e --- /dev/null +++ b/packages/react-hooks/src/memo.ts @@ -0,0 +1,13 @@ +// Copyright 2017-2020 @polkadot/react-hooks authors & contributors +// This software may be modified and distributed under the terms +// of the Apache-2.0 license. See the LICENSE file for details. + +import createMemo from 'memoizee'; + +// Normalize via JSON.stringify, allow e.g. AccountId -> ss58 +// eslint-disable-next-line @typescript-eslint/unbound-method +const normalizer = JSON.stringify; + +export default function memo (inner: T): T { + return createMemo(inner, { normalizer }); +} diff --git a/packages/react-hooks/src/useCall.tsx b/packages/react-hooks/src/useCall.tsx index e0806ecb35..14b4b75228 100644 --- a/packages/react-hooks/src/useCall.tsx +++ b/packages/react-hooks/src/useCall.tsx @@ -88,7 +88,9 @@ function subscribe (mounted: MountedRef, tracker: TrackerRef, fn: TrackFn | tracker.current.count++; ((transformed: any): void => { - setTimeout(() => setValue(transformed), 0); + setTimeout((): void => { + mounted.current && tracker.current.isActive && setValue(transformed); + }, 0); })(withParams ? [params, transform(value)] : transform(value)); } }); diff --git a/packages/react-signer/src/Checks/index.tsx b/packages/react-signer/src/Checks/index.tsx index 02e425eced..fa484bc9f0 100644 --- a/packages/react-signer/src/Checks/index.tsx +++ b/packages/react-signer/src/Checks/index.tsx @@ -26,11 +26,10 @@ export default function Checks ({ accountId, className, extrinsic }: Props): Rea const [dispatchInfo, setDispatchInfo] = useState(null); useEffect((): void => { - if (accountId && extrinsic?.paymentInfo && api.rpc.payment?.queryInfo) { + accountId && extrinsic?.paymentInfo && api.rpc.payment?.queryInfo && extrinsic .paymentInfo(accountId) .then(setDispatchInfo); - } }, [api, accountId, extrinsic]); if (!dispatchInfo) { diff --git a/yarn.lock b/yarn.lock index a87757fb47..ac88856f74 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2765,56 +2765,56 @@ __metadata: languageName: node linkType: hard -"@polkadot/api-contract@npm:^1.6.0-beta.28": - version: 1.6.0-beta.28 - resolution: "@polkadot/api-contract@npm:1.6.0-beta.28" +"@polkadot/api-contract@npm:^1.6.1": + version: 1.6.1 + resolution: "@polkadot/api-contract@npm:1.6.1" dependencies: "@babel/runtime": ^7.8.4 - "@polkadot/api": 1.6.0-beta.28 - "@polkadot/rpc-core": 1.6.0-beta.28 - "@polkadot/types": 1.6.0-beta.28 + "@polkadot/api": 1.6.1 + "@polkadot/rpc-core": 1.6.1 + "@polkadot/types": 1.6.1 "@polkadot/util": ^2.6.2 bn.js: ^5.1.1 rxjs: ^6.5.4 - checksum: 2/f199f996c521be7c88a5754565842b6f30029bcca41a5a19c91f667fe458543d052c854d19ee9b4c991991e2d4a39df4c79d2c10d45592fabc875e1b043cd29b + checksum: 2/6877fd0a691c776cac10df6941e81d40e528f71c628ba813ccf2f43219bd0eecac8b3eb77dff9ea031e7ae3f503b7a504ab4b2283d34ed64dea4f184479402c5 languageName: node linkType: hard -"@polkadot/api-derive@npm:1.6.0-beta.28": - version: 1.6.0-beta.28 - resolution: "@polkadot/api-derive@npm:1.6.0-beta.28" +"@polkadot/api-derive@npm:1.6.1": + version: 1.6.1 + resolution: "@polkadot/api-derive@npm:1.6.1" dependencies: "@babel/runtime": ^7.8.4 - "@polkadot/api": 1.6.0-beta.28 - "@polkadot/rpc-core": 1.6.0-beta.28 - "@polkadot/rpc-provider": 1.6.0-beta.28 - "@polkadot/types": 1.6.0-beta.28 + "@polkadot/api": 1.6.1 + "@polkadot/rpc-core": 1.6.1 + "@polkadot/rpc-provider": 1.6.1 + "@polkadot/types": 1.6.1 "@polkadot/util": ^2.6.2 "@polkadot/util-crypto": ^2.6.2 bn.js: ^5.1.1 memoizee: ^0.4.14 rxjs: ^6.5.4 - checksum: 2/0bf002a4e2a3e4e1cae760e50980a54974b026271421bfb2436ac3505c9802319b72818592ff79893abb65e09c4e835df89f8b9d8486f93a80dc9737dd527c87 + checksum: 2/2102bd01d7b9dd0531c8e14626bf0735544517354dd4f539c8319abfeb6fd5e9e95a75076bdf411acd5c61a4470e33613023fc92f965b3e167181ae6fc062ef4 languageName: node linkType: hard -"@polkadot/api@npm:^1.6.0-beta.28": - version: 1.6.0-beta.28 - resolution: "@polkadot/api@npm:1.6.0-beta.28" +"@polkadot/api@npm:^1.6.1": + version: 1.6.1 + resolution: "@polkadot/api@npm:1.6.1" dependencies: "@babel/runtime": ^7.8.4 - "@polkadot/api-derive": 1.6.0-beta.28 + "@polkadot/api-derive": 1.6.1 "@polkadot/keyring": ^2.6.2 - "@polkadot/metadata": 1.6.0-beta.28 - "@polkadot/rpc-core": 1.6.0-beta.28 - "@polkadot/rpc-provider": 1.6.0-beta.28 - "@polkadot/types": 1.6.0-beta.28 + "@polkadot/metadata": 1.6.1 + "@polkadot/rpc-core": 1.6.1 + "@polkadot/rpc-provider": 1.6.1 + "@polkadot/types": 1.6.1 "@polkadot/util": ^2.6.2 "@polkadot/util-crypto": ^2.6.2 bn.js: ^5.1.1 eventemitter3: ^4.0.0 rxjs: ^6.5.4 - checksum: 2/b539969aa9a502da96f52042d8a1a5041d10c9bb18f3a3275ecba2d85daade5bf6b63c70d3e0ae8723af6cf3e2e80f54a4eb983572c32b63cb660abc53f86a59 + checksum: 2/7d5503ad16be5af215b549f6b9f3d550fc31208b980cf2523de6f1dc76d4557656269958ee19b6ae8d422bb748eb2929ca088a84cf0a5c57946244870e2cad83 languageName: node linkType: hard @@ -2864,7 +2864,7 @@ __metadata: resolution: "@polkadot/app-contracts@workspace:packages/page-contracts" dependencies: "@babel/runtime": ^7.8.7 - "@polkadot/api-contract": ^1.6.0-beta.28 + "@polkadot/api-contract": ^1.6.1 languageName: unknown linkType: soft @@ -3176,14 +3176,14 @@ __metadata: languageName: node linkType: hard -"@polkadot/jsonrpc@npm:1.6.0-beta.28": - version: 1.6.0-beta.28 - resolution: "@polkadot/jsonrpc@npm:1.6.0-beta.28" +"@polkadot/jsonrpc@npm:1.6.1": + version: 1.6.1 + resolution: "@polkadot/jsonrpc@npm:1.6.1" dependencies: "@babel/runtime": ^7.8.4 - "@polkadot/types": 1.6.0-beta.28 + "@polkadot/types": 1.6.1 "@polkadot/util": ^2.6.2 - checksum: 2/fef65b236a5deb741bd022b8c45422133785957b0e1f50cd8596bdc6026430df7c3e32847e20e09a07daf6494bca67f4c79ed5b0213cb9aaf1ad91fba19313a6 + checksum: 2/0b59da9c85bdf46f6162db676fd66d3766abced809bfe1616177b25466d7e7a005ae27601fb099ad9783e46500de93931a7f691629ac02b7033c369b47f06711 languageName: node linkType: hard @@ -3198,16 +3198,16 @@ __metadata: languageName: node linkType: hard -"@polkadot/metadata@npm:1.6.0-beta.28": - version: 1.6.0-beta.28 - resolution: "@polkadot/metadata@npm:1.6.0-beta.28" +"@polkadot/metadata@npm:1.6.1": + version: 1.6.1 + resolution: "@polkadot/metadata@npm:1.6.1" dependencies: "@babel/runtime": ^7.8.4 - "@polkadot/types": 1.6.0-beta.28 + "@polkadot/types": 1.6.1 "@polkadot/util": ^2.6.2 "@polkadot/util-crypto": ^2.6.2 bn.js: ^5.1.1 - checksum: 2/1cceff15745c5a8b81fff1731f7cff69db624dc42fb593e969b68e2313531141700d64dfb05ce8469fe281e9dd94f17e5268cd4b3b2866a01da971134ca7d779 + checksum: 2/08b5c9591c9844b61d35d78335eae8b95fc0751c16cbad12c4a709370b9e9ee7e4004bc35c1b467d0279d1a4b73e8ecf965cabd4b43ae03f1761eb8950cebcc0 languageName: node linkType: hard @@ -3216,7 +3216,7 @@ __metadata: resolution: "@polkadot/react-api@workspace:packages/react-api" dependencies: "@babel/runtime": ^7.8.7 - "@polkadot/api": ^1.6.0-beta.28 + "@polkadot/api": ^1.6.1 "@polkadot/extension-dapp": ^0.22.1 rxjs-compat: ^6.5.4 languageName: unknown @@ -3262,6 +3262,8 @@ __metadata: resolution: "@polkadot/react-hooks@workspace:packages/react-hooks" dependencies: "@babel/runtime": ^7.8.7 + "@types/memoizee": ^0.4.3 + memoizee: ^0.4.14 languageName: unknown linkType: soft @@ -3328,37 +3330,37 @@ __metadata: languageName: unknown linkType: soft -"@polkadot/rpc-core@npm:1.6.0-beta.28": - version: 1.6.0-beta.28 - resolution: "@polkadot/rpc-core@npm:1.6.0-beta.28" +"@polkadot/rpc-core@npm:1.6.1": + version: 1.6.1 + resolution: "@polkadot/rpc-core@npm:1.6.1" dependencies: "@babel/runtime": ^7.8.4 - "@polkadot/jsonrpc": 1.6.0-beta.28 - "@polkadot/metadata": 1.6.0-beta.28 - "@polkadot/rpc-provider": 1.6.0-beta.28 - "@polkadot/types": 1.6.0-beta.28 + "@polkadot/jsonrpc": 1.6.1 + "@polkadot/metadata": 1.6.1 + "@polkadot/rpc-provider": 1.6.1 + "@polkadot/types": 1.6.1 "@polkadot/util": ^2.6.2 memoizee: ^0.4.14 rxjs: ^6.5.4 - checksum: 2/70f0c58a0b17dd64ac721d2687fc1a3c958d751123a1486ade7a820c1f202d8809c412e5f6f4f5fa3d51ec8cae4350f361086f7a1e0a4097947315ae9c4af17d + checksum: 2/554113e42a362fb59dfc010129518c6f7c024b39427b8d58a54be65b589b76606ab89010733db807b272541b69a2533f914ec885a4a29cba1da9a78ed74da90b languageName: node linkType: hard -"@polkadot/rpc-provider@npm:1.6.0-beta.28": - version: 1.6.0-beta.28 - resolution: "@polkadot/rpc-provider@npm:1.6.0-beta.28" +"@polkadot/rpc-provider@npm:1.6.1": + version: 1.6.1 + resolution: "@polkadot/rpc-provider@npm:1.6.1" dependencies: "@babel/runtime": ^7.8.4 - "@polkadot/jsonrpc": 1.6.0-beta.28 - "@polkadot/metadata": 1.6.0-beta.28 - "@polkadot/types": 1.6.0-beta.28 + "@polkadot/jsonrpc": 1.6.1 + "@polkadot/metadata": 1.6.1 + "@polkadot/types": 1.6.1 "@polkadot/util": ^2.6.2 "@polkadot/util-crypto": ^2.6.2 bn.js: ^5.1.1 eventemitter3: ^4.0.0 isomorphic-fetch: ^2.2.1 websocket: ^1.0.31 - checksum: 2/ed3c826c87a38d6e147398d1ab997ea8acd72bdde260c668f0370ef49b56f54bf7d37575ba1d3e9d12149730e5b824f957e1e060959ff3d8d14765cebc10fdd2 + checksum: 2/a93bb04403b721d9ac161aa4a20192cbfeffbe37be2085a28f59dd4fa9262c107f1b599a4a0c298fd513ee45d3f9b4b950cccb511b3e9a57ae3566312c9bd736 languageName: node linkType: hard @@ -3371,19 +3373,19 @@ __metadata: languageName: node linkType: hard -"@polkadot/types@npm:^1.6.0-beta.28": - version: 1.6.0-beta.28 - resolution: "@polkadot/types@npm:1.6.0-beta.28" +"@polkadot/types@npm:^1.6.1": + version: 1.6.1 + resolution: "@polkadot/types@npm:1.6.1" dependencies: "@babel/runtime": ^7.8.4 - "@polkadot/metadata": 1.6.0-beta.28 + "@polkadot/metadata": 1.6.1 "@polkadot/util": ^2.6.2 "@polkadot/util-crypto": ^2.6.2 "@types/bn.js": ^4.11.6 bn.js: ^5.1.1 memoizee: ^0.4.14 rxjs: ^6.5.4 - checksum: 2/58faa8d0ce629037a61d16029aa80cca9775dc181f7e5480daef2a5665eb8a53ed811afd66fd4a47acf70add4337e8bcbbaba92a69935fde5e0abbf85558c07e + checksum: 2/7f6c78bc727ec2c758baea7ab6bad4d2ee25ff4fa809396e6c4630332d4e0e555049bd167332a82332839dc8141d5e19401eecc6172669d3cdfacf1d6ef102f8 languageName: node linkType: hard @@ -3740,6 +3742,13 @@ __metadata: languageName: node linkType: hard +"@types/memoizee@npm:^0.4.3": + version: 0.4.3 + resolution: "@types/memoizee@npm:0.4.3" + checksum: 2/39f75aa4fd13e38dd8fd6bcd7e2eb7db3ed05ac5546d7a908f869bac2b6050bb7437434516dbfa12803f53928df7a9674dceb249a016c54a68dca2fdefab5794 + languageName: node + linkType: hard + "@types/minimatch@npm:*, @types/minimatch@npm:3.0.3": version: 3.0.3 resolution: "@types/minimatch@npm:3.0.3"