useCallback in all staking callbacks (#2376)
* Add React.emomo to some components * Linting * useCallback for callbacks * Additional useCallback impl.
This commit is contained in:
parent
31211324e5
commit
83a2ddedd4
@ -4,7 +4,7 @@
|
||||
|
||||
import { BareProps as Props } from '@polkadot/react-components/types';
|
||||
|
||||
import React, { useMemo, useState } from 'react';
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
import store from 'store';
|
||||
import styled from 'styled-components';
|
||||
import { defaultColor, chainColors, emptyColor, nodeColors } from '@polkadot/apps-config/ui/general';
|
||||
@ -46,23 +46,35 @@ function Apps ({ className }: Props): React.ReactElement<Props> {
|
||||
}, [systemChain, systemName]);
|
||||
const { isCollapsed, isMenu, isMenuOpen } = sidebar;
|
||||
|
||||
const _setSidebar = (update: Partial<SidebarState>): void =>
|
||||
setSidebar(store.set('sidebar', { ...sidebar, ...update }));
|
||||
const _collapse = (): void =>
|
||||
_setSidebar({ isCollapsed: !isCollapsed });
|
||||
const _toggleMenu = (): void =>
|
||||
_setSidebar({ isCollapsed: false, isMenuOpen: true });
|
||||
const _handleResize = (): void => {
|
||||
const transition = window.innerWidth < SIDEBAR_MENU_THRESHOLD
|
||||
? SideBarTransition.MINIMISED_AND_EXPANDED
|
||||
: SideBarTransition.EXPANDED_AND_MAXIMISED;
|
||||
const _setSidebar = useCallback(
|
||||
(update: Partial<SidebarState>): void =>
|
||||
setSidebar((sidebar: SidebarState) =>
|
||||
store.set('sidebar', { ...sidebar, ...update })
|
||||
),
|
||||
[]
|
||||
);
|
||||
const _collapse = useCallback(
|
||||
(): void => _setSidebar({ isCollapsed: !isCollapsed }),
|
||||
[isCollapsed]
|
||||
);
|
||||
const _toggleMenu = useCallback(
|
||||
(): void => _setSidebar({ isCollapsed: false, isMenuOpen: true }),
|
||||
[]
|
||||
);
|
||||
const _handleResize = useCallback(
|
||||
(): void => {
|
||||
const transition = window.innerWidth < SIDEBAR_MENU_THRESHOLD
|
||||
? SideBarTransition.MINIMISED_AND_EXPANDED
|
||||
: SideBarTransition.EXPANDED_AND_MAXIMISED;
|
||||
|
||||
_setSidebar({
|
||||
isMenu: transition === SideBarTransition.MINIMISED_AND_EXPANDED,
|
||||
isMenuOpen: false,
|
||||
transition
|
||||
});
|
||||
};
|
||||
_setSidebar({
|
||||
isMenu: transition === SideBarTransition.MINIMISED_AND_EXPANDED,
|
||||
isMenuOpen: false,
|
||||
transition
|
||||
});
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
|
||||
import { SIDEBAR_MENU_THRESHOLD } from '../constants';
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { Responsive } from 'semantic-ui-react';
|
||||
import routing from '@polkadot/apps-routing';
|
||||
@ -38,8 +38,14 @@ function SideBar ({ className, collapse, handleResize, isCollapsed, isMenuOpen,
|
||||
}, { network: false })
|
||||
);
|
||||
|
||||
const _toggleModal = (name: string): () => void =>
|
||||
(): void => setModals({ ...modals, [name]: !modals[name] });
|
||||
const _toggleModal = useCallback(
|
||||
(name: string): () => void =>
|
||||
(): void => setModals((modals: Record<string, boolean>) => ({
|
||||
...modals,
|
||||
[name]: !modals[name]
|
||||
})),
|
||||
[]
|
||||
);
|
||||
|
||||
return (
|
||||
<Responsive
|
||||
@ -51,7 +57,7 @@ function SideBar ({ className, collapse, handleResize, isCollapsed, isMenuOpen,
|
||||
onClick={toggleMenu}
|
||||
/>
|
||||
{routing.routes.map((route): React.ReactNode => (
|
||||
route && route.Modal
|
||||
route?.Modal
|
||||
? route.Modal && modals[route.name]
|
||||
? (
|
||||
<route.Modal
|
||||
@ -207,11 +213,20 @@ export default styled(SideBar)`
|
||||
align-self: flex-end;
|
||||
flex-grow: 0;
|
||||
padding: 0 !important;
|
||||
position: relative;
|
||||
width: inherit;
|
||||
|
||||
.text {
|
||||
padding-left: 0.5rem;
|
||||
}
|
||||
|
||||
.ui--Badge {
|
||||
margin: 0;
|
||||
position: absolute;
|
||||
right: 0.5rem;
|
||||
top: 0.55rem;
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.apps--SideBar-collapse {
|
||||
|
||||
@ -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 React, { useState } from 'react';
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { useAccounts, useApi } from '@polkadot/react-hooks';
|
||||
|
||||
@ -19,12 +19,15 @@ export default function Accounts ({ className }: Props): React.ReactElement<Prop
|
||||
const { isApiReady } = useApi();
|
||||
const [isHidden, setIsHidden] = useState(false);
|
||||
|
||||
const _onClose = useCallback(
|
||||
(): void => setIsHidden(true),
|
||||
[]
|
||||
);
|
||||
|
||||
if (!isApiReady || hasAccounts || isHidden) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const _onClose = (): void => setIsHidden(true);
|
||||
|
||||
return (
|
||||
<BaseOverlay
|
||||
className={className}
|
||||
|
||||
@ -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 React, { useState } from 'react';
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { Icon } from '@polkadot/react-components';
|
||||
|
||||
@ -16,12 +16,15 @@ interface Props {
|
||||
function BaseOverlay ({ children, className, icon, type }: Props): React.ReactElement<Props> | null {
|
||||
const [isHidden, setIsHidden] = useState(false);
|
||||
|
||||
const _onClose = useCallback(
|
||||
(): void => setIsHidden(true),
|
||||
[]
|
||||
);
|
||||
|
||||
if (isHidden) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const _onClose = (): void => setIsHidden(true);
|
||||
|
||||
return (
|
||||
<div className={`${className} ${type === 'error' ? 'isError' : 'isInfo'}`}>
|
||||
<div className='content'>
|
||||
|
||||
@ -6,7 +6,7 @@ import { DeriveAccountInfo } from '@polkadot/api-derive/types';
|
||||
import { ActionStatus } from '@polkadot/react-components/Status/types';
|
||||
import { RecoveryConfig } from '@polkadot/types/interfaces';
|
||||
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import React, { useCallback, useState, useEffect } from 'react';
|
||||
import { Label } from 'semantic-ui-react';
|
||||
import styled from 'styled-components';
|
||||
import { AddressInfo, AddressSmall, Badge, Button, ChainLock, Forget, Icon, IdentityIcon, InputTags, LinkExternal, Menu, Popup, Input } from '@polkadot/react-components';
|
||||
@ -57,7 +57,10 @@ function Account ({ address, className, filter, isFavorite, toggleFavorite }: Pr
|
||||
const [isSettingsOpen, toggleSettings] = useToggle();
|
||||
const [isTransferOpen, toggleTransfer] = useToggle();
|
||||
|
||||
const _setTags = (tags: string[]): void => setTags(tags.sort());
|
||||
const _setTags = useCallback(
|
||||
(tags: string[]): void => setTags(tags.sort()),
|
||||
[]
|
||||
);
|
||||
|
||||
useEffect((): void => {
|
||||
const { identity, nickname } = info || {};
|
||||
|
||||
@ -9,7 +9,7 @@ import React, { useEffect, useState } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import keyring from '@polkadot/ui-keyring';
|
||||
import { getLedger, isLedger } from '@polkadot/react-api';
|
||||
import { useAccounts, useFavorites } from '@polkadot/react-hooks';
|
||||
import { useAccounts, useFavorites, useToggle } from '@polkadot/react-hooks';
|
||||
import { Button, Input, Table } from '@polkadot/react-components';
|
||||
|
||||
import CreateModal from './modals/Create';
|
||||
@ -39,9 +39,9 @@ async function queryLedger (): Promise<void> {
|
||||
function Overview ({ className, onStatusChange }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const { allAccounts, hasAccounts } = useAccounts();
|
||||
const [isCreateOpen, setIsCreateOpen] = useState(false);
|
||||
const [isImportOpen, setIsImportOpen] = useState(false);
|
||||
const [isQrOpen, setIsQrOpen] = useState(false);
|
||||
const [isCreateOpen, toggleCreate] = useToggle();
|
||||
const [isImportOpen, toggleImport] = useToggle();
|
||||
const [isQrOpen, toggleQr] = useToggle();
|
||||
const [favorites, toggleFavorite] = useFavorites(STORE_FAVS);
|
||||
const [sortedAccounts, setSortedAccounts] = useState<SortedAccount[]>([]);
|
||||
const [filter, setFilter] = useState<string>('');
|
||||
@ -66,28 +66,24 @@ function Overview ({ className, onStatusChange }: Props): React.ReactElement<Pro
|
||||
);
|
||||
}, [allAccounts, favorites]);
|
||||
|
||||
const _toggleCreate = (): void => setIsCreateOpen(!isCreateOpen);
|
||||
const _toggleImport = (): void => setIsImportOpen(!isImportOpen);
|
||||
const _toggleQr = (): void => setIsQrOpen(!isQrOpen);
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
<Banner />
|
||||
{isCreateOpen && (
|
||||
<CreateModal
|
||||
onClose={_toggleCreate}
|
||||
onClose={toggleCreate}
|
||||
onStatusChange={onStatusChange}
|
||||
/>
|
||||
)}
|
||||
{isImportOpen && (
|
||||
<ImportModal
|
||||
onClose={_toggleImport}
|
||||
onClose={toggleImport}
|
||||
onStatusChange={onStatusChange}
|
||||
/>
|
||||
)}
|
||||
{isQrOpen && (
|
||||
<QrModal
|
||||
onClose={_toggleQr}
|
||||
onClose={toggleQr}
|
||||
onStatusChange={onStatusChange}
|
||||
/>
|
||||
)}
|
||||
@ -96,21 +92,21 @@ function Overview ({ className, onStatusChange }: Props): React.ReactElement<Pro
|
||||
icon='add'
|
||||
isPrimary
|
||||
label={t('Add account')}
|
||||
onClick={_toggleCreate}
|
||||
onClick={toggleCreate}
|
||||
/>
|
||||
<Button.Or />
|
||||
<Button
|
||||
icon='sync'
|
||||
isPrimary
|
||||
label={t('Restore JSON')}
|
||||
onClick={_toggleImport}
|
||||
onClick={toggleImport}
|
||||
/>
|
||||
<Button.Or />
|
||||
<Button
|
||||
icon='qrcode'
|
||||
isPrimary
|
||||
label={t('Add via Qr')}
|
||||
onClick={_toggleQr}
|
||||
onClick={toggleQr}
|
||||
/>
|
||||
{isLedger() && (
|
||||
<>
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
|
||||
import { KeypairType } from '@polkadot/util-crypto/types';
|
||||
|
||||
import React, { useContext, useEffect, useMemo, useState } from 'react';
|
||||
import React, { useCallback, useContext, useEffect, useMemo, useState } from 'react';
|
||||
import { Button, Dropdown, Icon, Input, Modal, StatusContext } from '@polkadot/react-components';
|
||||
import keyring from '@polkadot/ui-keyring';
|
||||
import { assert, u8aToHex } from '@polkadot/util';
|
||||
@ -58,17 +58,22 @@ export default function InjectKeys ({ onClose }: Props): React.ReactElement<Prop
|
||||
}
|
||||
}, [crypto, suri]);
|
||||
|
||||
const _onSubmit = (): void =>
|
||||
queueRpc({
|
||||
const _onSubmit = useCallback(
|
||||
(): void => queueRpc({
|
||||
rpc: { section: 'author', method: 'insertKey' } as any,
|
||||
values: [keyType, suri, publicKey]
|
||||
});
|
||||
const _cryptoOptions = CRYPTO_MAP[keyType].map((value): { text: string; value: KeypairType } => ({
|
||||
text: value === 'ed25519'
|
||||
? t('ed25519, Edwards')
|
||||
: t('sr15519, Schnorrkel'),
|
||||
value
|
||||
}));
|
||||
}),
|
||||
[keyType, publicKey, suri]
|
||||
);
|
||||
const _cryptoOptions = useMemo(
|
||||
() => CRYPTO_MAP[keyType].map((value): { text: string; value: KeypairType } => ({
|
||||
text: value === 'ed25519'
|
||||
? t('ed25519, Edwards')
|
||||
: t('sr15519, Schnorrkel'),
|
||||
value
|
||||
})),
|
||||
[keyType, t]
|
||||
);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
|
||||
@ -8,7 +8,7 @@ import { AccountId, EraIndex, Exposure, StakingLedger, ValidatorPrefs } from '@p
|
||||
import { Codec, ITuple } from '@polkadot/types/types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import React, { useContext, useEffect, useState } from 'react';
|
||||
import React, { useCallback, useContext, useEffect, useState } from 'react';
|
||||
import { Trans } from 'react-i18next';
|
||||
import styled from 'styled-components';
|
||||
import { ApiPromise } from '@polkadot/api';
|
||||
@ -162,11 +162,13 @@ function Account ({ allStashes, className, isOwnStash, next, onUpdateType, rewar
|
||||
]);
|
||||
}, [rewards]);
|
||||
|
||||
const _doPayout = (): void =>
|
||||
queueExtrinsic({
|
||||
const _doPayout = useCallback(
|
||||
(): void => queueExtrinsic({
|
||||
accountId: controllerId,
|
||||
extrinsic: createPayout(api, payoutRewards)
|
||||
});
|
||||
}),
|
||||
[api, controllerId, payoutRewards]
|
||||
);
|
||||
|
||||
return (
|
||||
<tr className={className}>
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
import { DerivedStakingOverview, DeriveStakerReward } from '@polkadot/api-derive/types';
|
||||
import { ActiveEraInfo, EraIndex } from '@polkadot/types/interfaces';
|
||||
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import { Button, Table } from '@polkadot/react-components';
|
||||
import { useCall, useApi, useOwnStashes } from '@polkadot/react-hooks';
|
||||
import { Option } from '@polkadot/types';
|
||||
@ -45,16 +45,24 @@ export default function Actions ({ allRewards, allStashes, className, isVisible,
|
||||
);
|
||||
}, [ownStashes, stashTypes]);
|
||||
|
||||
const _toggleNewStake = (): void => setIsNewStateOpen(!isNewStakeOpen);
|
||||
const _onUpdateType = (stashId: string, type: 'validator' | 'nominator' | 'started' | 'other'): void =>
|
||||
setStashTypes({
|
||||
...stashTypes,
|
||||
[stashId]: type === 'validator'
|
||||
? 1
|
||||
: type === 'nominator'
|
||||
? 5
|
||||
: 9
|
||||
});
|
||||
const _toggleNewStake = useCallback(
|
||||
(): void => setIsNewStateOpen(
|
||||
(isNewStakeOpen: boolean) => !isNewStakeOpen
|
||||
),
|
||||
[]
|
||||
);
|
||||
const _onUpdateType = useCallback(
|
||||
(stashId: string, type: 'validator' | 'nominator' | 'started' | 'other'): void =>
|
||||
setStashTypes((stashTypes: Record<string, number>) => ({
|
||||
...stashTypes,
|
||||
[stashId]: type === 'validator'
|
||||
? 1
|
||||
: type === 'nominator'
|
||||
? 5
|
||||
: 9
|
||||
})),
|
||||
[]
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={`${className} ${!isVisible && 'staking--hidden'}`}>
|
||||
|
||||
@ -6,7 +6,7 @@ import { AccountId, Balance, RewardPoint } from '@polkadot/types/interfaces';
|
||||
import { DeriveAccountInfo, DerivedStakingQuery, DerivedHeartbeatAuthor } from '@polkadot/api-derive/types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import ApiPromise from '@polkadot/api/promise';
|
||||
import { AddressMini, AddressSmall, Badge, Icon } from '@polkadot/react-components';
|
||||
import { useApi, useCall } from '@polkadot/react-hooks';
|
||||
@ -122,16 +122,25 @@ function Address ({ address, className, filterName, hasQueries, heartbeat, isAut
|
||||
);
|
||||
}, [address, filterName, info]);
|
||||
|
||||
const _onFavorite = (): void => toggleFavorite(address);
|
||||
const _onQueryStats = (): void => {
|
||||
window.location.hash = `/staking/query/${address}`;
|
||||
};
|
||||
const _toggleNominators = (event: React.SyntheticEvent): void => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
const _onFavorite = useCallback(
|
||||
(): void => toggleFavorite(address),
|
||||
[address]
|
||||
);
|
||||
const _onQueryStats = useCallback(
|
||||
(): void => {
|
||||
window.location.hash = `/staking/query/${address}`;
|
||||
},
|
||||
[address]
|
||||
);
|
||||
const _toggleNominators = useCallback(
|
||||
(event: React.SyntheticEvent): void => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
setIsExpanded(!isExpanded);
|
||||
};
|
||||
setIsExpanded((isExpanded: boolean) => !isExpanded);
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
return (
|
||||
<tr className={`${className} ${isAuthor && 'isHighlight'} ${!isVisible && 'staking--hidden'}`}>
|
||||
|
||||
@ -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 React, { useState } from 'react';
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import { useParams } from 'react-router-dom';
|
||||
import { Button, InputAddressSimple } from '@polkadot/react-components';
|
||||
|
||||
@ -18,11 +18,14 @@ export default function Query ({ className }: Props): React.ReactElement<Props>
|
||||
const { value } = useParams();
|
||||
const [validatorId, setValidatorId] = useState<string | null>(value || null);
|
||||
|
||||
const _onQuery = (): void => {
|
||||
if (validatorId) {
|
||||
window.location.hash = `/staking/query/${validatorId}`;
|
||||
}
|
||||
};
|
||||
const _onQuery = useCallback(
|
||||
(): void => {
|
||||
if (validatorId) {
|
||||
window.location.hash = `/staking/query/${validatorId}`;
|
||||
}
|
||||
},
|
||||
[validatorId]
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
|
||||
import { ValidatorInfo } from './types';
|
||||
|
||||
import React from 'react';
|
||||
import React, { useCallback } from 'react';
|
||||
import { AddressSmall, Icon } from '@polkadot/react-components';
|
||||
import { FormatBalance } from '@polkadot/react-query';
|
||||
import { formatNumber } from '@polkadot/util';
|
||||
@ -18,10 +18,17 @@ interface Props {
|
||||
|
||||
function Validator ({ info: { accountId, bondOther, bondOwn, bondTotal, commissionPer, isCommission, isFavorite, isNominating, key, numNominators, rankOverall, rewardPayout, validatorPayment }, toggleFavorite }: Props): React.ReactElement<Props> {
|
||||
const { t } = useTranslation();
|
||||
const _onFavorite = (): void => toggleFavorite(key);
|
||||
const _onQueryStats = (): void => {
|
||||
window.location.hash = `/staking/query/${key}`;
|
||||
};
|
||||
|
||||
const _onFavorite = useCallback(
|
||||
(): void => toggleFavorite(key),
|
||||
[key]
|
||||
);
|
||||
const _onQueryStats = useCallback(
|
||||
(): void => {
|
||||
window.location.hash = `/staking/query/${key}`;
|
||||
},
|
||||
[key]
|
||||
);
|
||||
|
||||
return (
|
||||
<tr className={`${isNominating && 'isHighlight'}`}>
|
||||
|
||||
@ -7,7 +7,7 @@ import { Balance, ValidatorPrefs, ValidatorPrefsTo196 } from '@polkadot/types/in
|
||||
import { ValidatorInfo } from './types';
|
||||
|
||||
import BN from 'bn.js';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import React, { useCallback, useEffect, useState } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { registry } from '@polkadot/react-api';
|
||||
import { Icon, InputBalance, Spinner, Table } from '@polkadot/react-components';
|
||||
@ -174,27 +174,30 @@ function Targets ({ className }: Props): React.ReactElement<Props> {
|
||||
const [{ sorted, sortBy, sortFromMax }, setSorted] = useState<{ sorted?: ValidatorInfo[]; sortBy: SortBy; sortFromMax: boolean }>({ sortBy: 'rankOverall', sortFromMax: true });
|
||||
const amount = useDebounce(_amount);
|
||||
|
||||
const _sort = (newSortBy: SortBy, unsorted = validators, isAdjust = true): void => {
|
||||
const newSortFromMax = isAdjust && newSortBy === sortBy ? !sortFromMax : true;
|
||||
const _sort = useCallback(
|
||||
(newSortBy: SortBy, unsorted: ValidatorInfo[] = validators, isAdjust = true): void => {
|
||||
const newSortFromMax = isAdjust && newSortBy === sortBy ? !sortFromMax : true;
|
||||
|
||||
setSorted({
|
||||
sortBy: newSortBy,
|
||||
sortFromMax: newSortFromMax,
|
||||
sorted: unsorted
|
||||
.sort((a, b): number =>
|
||||
newSortFromMax
|
||||
? a[newSortBy] - b[newSortBy]
|
||||
: b[newSortBy] - a[newSortBy]
|
||||
)
|
||||
.sort((a, b): number =>
|
||||
a.isFavorite === b.isFavorite
|
||||
? 0
|
||||
: a.isFavorite
|
||||
? -1
|
||||
: 1
|
||||
)
|
||||
});
|
||||
};
|
||||
setSorted({
|
||||
sortBy: newSortBy,
|
||||
sortFromMax: newSortFromMax,
|
||||
sorted: unsorted
|
||||
.sort((a, b): number =>
|
||||
newSortFromMax
|
||||
? a[newSortBy] - b[newSortBy]
|
||||
: b[newSortBy] - a[newSortBy]
|
||||
)
|
||||
.sort((a, b): number =>
|
||||
a.isFavorite === b.isFavorite
|
||||
? 0
|
||||
: a.isFavorite
|
||||
? -1
|
||||
: 1
|
||||
)
|
||||
});
|
||||
},
|
||||
[validators]
|
||||
);
|
||||
|
||||
useEffect((): void => {
|
||||
if (electedInfo) {
|
||||
|
||||
@ -4,17 +4,18 @@
|
||||
|
||||
import { StringOrNull } from '@polkadot/react-components/types';
|
||||
|
||||
import { useState } from 'react';
|
||||
import { useCallback, useState } from 'react';
|
||||
|
||||
export default function useAccountId (initialValue: StringOrNull = null, onChangeAccountId?: (_: StringOrNull) => void): [StringOrNull, (_: StringOrNull) => void] {
|
||||
const [accountId, setAccountId] = useState<StringOrNull>(initialValue);
|
||||
|
||||
return [
|
||||
accountId,
|
||||
const _setAccountId = useCallback(
|
||||
(accountId: StringOrNull = null): void => {
|
||||
setAccountId(accountId);
|
||||
|
||||
onChangeAccountId && onChangeAccountId(accountId);
|
||||
}
|
||||
];
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
return [accountId, _setAccountId];
|
||||
}
|
||||
@ -2,6 +2,8 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import store from 'store';
|
||||
import useApi from './useApi';
|
||||
|
||||
@ -9,9 +11,8 @@ import useApi from './useApi';
|
||||
export default function useCacheKey <T> (storageKeyBase: string): [(defaultValue?: T) => T | undefined, (value: T) => T] {
|
||||
const { api, isDevelopment } = useApi();
|
||||
const STORAGE_KEY = `${storageKeyBase}:${isDevelopment ? 'development' : api.genesisHash}`;
|
||||
const getter = useCallback((): T | undefined => store.get(STORAGE_KEY), []);
|
||||
const setter = useCallback((value: T): T => store.set(STORAGE_KEY, value), []);
|
||||
|
||||
return [
|
||||
(): T | undefined => store.get(STORAGE_KEY),
|
||||
(value: T): T => store.set(STORAGE_KEY, value)
|
||||
];
|
||||
return [getter, setter];
|
||||
}
|
||||
|
||||
@ -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 { useState } from 'react';
|
||||
import { useCallback, useState } from 'react';
|
||||
|
||||
import useCacheKey from './useCacheKey';
|
||||
|
||||
@ -10,15 +10,16 @@ import useCacheKey from './useCacheKey';
|
||||
export default function useFavorites (storageKeyBase: string): [string[], (address: string) => void] {
|
||||
const [getCache, setCache] = useCacheKey<string[]>(storageKeyBase);
|
||||
const [favorites, setFavorites] = useState<string[]>(getCache() || []);
|
||||
|
||||
const _toggleFavorite = (address: string): void =>
|
||||
setFavorites(
|
||||
setCache(
|
||||
const toggleFavorite = useCallback(
|
||||
(address: string): void => setFavorites(
|
||||
(favorites: string[]) => setCache(
|
||||
favorites.includes(address)
|
||||
? favorites.filter((accountId): boolean => address !== accountId)
|
||||
: [...favorites, address]
|
||||
)
|
||||
);
|
||||
),
|
||||
[]
|
||||
);
|
||||
|
||||
return [favorites, _toggleFavorite];
|
||||
return [favorites, toggleFavorite];
|
||||
}
|
||||
@ -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 { useMemo, useState } from 'react';
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
|
||||
type FormField<T> = [
|
||||
T | null,
|
||||
@ -20,10 +20,11 @@ export default function useFormField<T> (defaultValue: T | null, validate: (_?:
|
||||
(): boolean => isTruthy<T>(value) && validate(value),
|
||||
[value]
|
||||
);
|
||||
const setter = useCallback((value?: T | null): void => setValue(value || null), []);
|
||||
|
||||
return [
|
||||
value,
|
||||
isValid,
|
||||
(value?: T | null): void => setValue(value || null)
|
||||
setter
|
||||
];
|
||||
}
|
||||
|
||||
@ -4,22 +4,28 @@
|
||||
|
||||
import { ModalState } from './types';
|
||||
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import useToggle from './useToggle';
|
||||
|
||||
export default function useModal (defaultIsOpen?: boolean, onOpen?: () => void, onClose?: () => void): ModalState {
|
||||
const [isOpen, , setIsOpen] = useToggle(defaultIsOpen || false);
|
||||
|
||||
return {
|
||||
isOpen,
|
||||
onOpen: (): void => {
|
||||
const _onOpen = useCallback(
|
||||
(): void => {
|
||||
setIsOpen(true);
|
||||
|
||||
onOpen && onOpen();
|
||||
},
|
||||
onClose: (): void => {
|
||||
[]
|
||||
);
|
||||
const _onClose = useCallback(
|
||||
(): void => {
|
||||
setIsOpen(false);
|
||||
|
||||
onClose && onClose();
|
||||
}
|
||||
};
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
return { isOpen, onClose: _onClose, onOpen: _onOpen };
|
||||
}
|
||||
@ -59,9 +59,9 @@ export default function useOwnEraRewards (): OwnRewards {
|
||||
const [state, setState] = useState<OwnRewards>({ rewardCount: 0 });
|
||||
|
||||
useEffect((): void => {
|
||||
if (available && nextParams) {
|
||||
setState(getRewards(available, nextParams));
|
||||
}
|
||||
available && nextParams && setState(
|
||||
getRewards(available, nextParams)
|
||||
);
|
||||
}, [available, nextParams]);
|
||||
|
||||
return state;
|
||||
@ -2,13 +2,15 @@
|
||||
// This software may be modified and distributed under the terms
|
||||
// of the Apache-2.0 license. See the LICENSE file for details.
|
||||
|
||||
import { useState } from 'react';
|
||||
import { useCallback, useState } from 'react';
|
||||
|
||||
// Simple wrapper for a true/false toggle
|
||||
export default function useToggle (defaultValue = false): [boolean, () => void, (value: boolean) => void] {
|
||||
const [isActive, setActive] = useState(defaultValue);
|
||||
const toggleActive = useCallback(
|
||||
(): void => setActive((isActive: boolean) => !isActive),
|
||||
[]
|
||||
);
|
||||
|
||||
const toggle = (): void => setActive(!isActive);
|
||||
|
||||
return [isActive, toggle, setActive];
|
||||
return [isActive, toggleActive, setActive];
|
||||
}
|
||||
|
||||
@ -22,6 +22,7 @@ function getExtrinsic<T extends TxDefs> (api: ApiPromise, txDef: T): Submittable
|
||||
const [section, method] = txDef[0].split('.');
|
||||
|
||||
assert(api.tx[section] && api.tx[section][method], `Unable to find api.tx.${section}.${method}`);
|
||||
|
||||
try {
|
||||
return api.tx[section][method](...(
|
||||
isFunction(txDef[1])
|
||||
|
||||
Loading…
Reference in New Issue
Block a user