Merge prev/current bags stash info (& React.memo) (#7267)

* Merge prev/current bags stash info (& React.memo)

* Adjust

* Adjust loading
This commit is contained in:
Jaco 2022-03-30 08:29:15 +02:00 committed by GitHub
parent cc56f65179
commit e182d20853
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 53 additions and 31 deletions

View File

@ -2,13 +2,13 @@
// SPDX-License-Identifier: Apache-2.0
import type { u64 } from '@polkadot/types';
import type { AccountId32 } from '@polkadot/types/interfaces';
import type { PalletBagsListListBag } from '@polkadot/types/lookup';
import type { StashNode } from './types';
import React, { useEffect, useMemo, useState } from 'react';
import React, { useEffect, useState } from 'react';
import { AddressMini, Spinner } from '@polkadot/react-components';
import { useIncrement } from '@polkadot/react-hooks';
import { FormatBalance } from '@polkadot/react-query';
import { formatNumber } from '@polkadot/util';
@ -22,27 +22,24 @@ interface Props {
stashNodes?: StashNode[];
}
export default function Bag ({ id, info, stashNodes }: Props): React.ReactElement<Props> {
function Bag ({ id, info, stashNodes }: Props): React.ReactElement<Props> {
const [[headId, trigger], setHeadId] = useState<[AccountId32 | null, number]>([null, 0]);
const [isLoading, setLoading] = useState(true);
const [trigger, doRefresh] = useIncrement(1);
const headId = useMemo(
() => stashNodes && stashNodes.length
? info.head.unwrapOr(null)
: null,
[info, stashNodes]
);
const list = useBagEntries(headId, trigger);
const [isCompleted, list] = useBagEntries(headId, trigger);
const bonded = useBonded(list);
useEffect((): void => {
info && stashNodes &&
setHeadId(([, trigger]) => [info.head.unwrapOr(null), ++trigger]);
}, [info, stashNodes]);
useEffect((): void => {
setLoading(
stashNodes && stashNodes.length
? list
? !bonded
: true
? !isCompleted || !bonded
: false
);
}, [bonded, list, stashNodes]);
}, [bonded, isCompleted, stashNodes]);
return (
<tr>
@ -52,7 +49,6 @@ export default function Bag ({ id, info, stashNodes }: Props): React.ReactElemen
<td className='address'>
{stashNodes?.map(({ stashId }) => (
<Stash
doRefresh={doRefresh}
isLoading={isLoading}
key={stashId}
list={bonded}
@ -71,3 +67,5 @@ export default function Bag ({ id, info, stashNodes }: Props): React.ReactElemen
</tr>
);
}
export default React.memo(Bag);

View File

@ -13,7 +13,6 @@ import { useTranslation } from '../translate';
interface Props {
className?: string;
doRefresh: () => void;
isLoading: boolean;
list?: ListNode[];
stashId: string;
@ -26,7 +25,7 @@ function findEntry (stashId: string, list: ListNode[] = []): [ListNode | null, b
return [entry, !!other, entry && other ? entry.index - other.index : 0];
}
function Stash ({ className, doRefresh, isLoading, list, stashId }: Props): React.ReactElement<Props> {
function Stash ({ className, isLoading, list, stashId }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const { api } = useApi();
const [stashInfo, canJump, jumpCount] = useMemo(
@ -45,7 +44,6 @@ function Stash ({ className, doRefresh, isLoading, list, stashId }: Props): Reac
icon='caret-up'
isDisabled={!canJump || isLoading}
label={t<string>('Move up {{jumpCount}}', { replace: { jumpCount } })}
onSuccess={doRefresh}
params={[stashInfo?.jump]}
tx={api.tx.bagsList.putInFrontOf}
/>
@ -53,7 +51,7 @@ function Stash ({ className, doRefresh, isLoading, list, stashId }: Props): Reac
);
}
export default styled(Stash)`
export default React.memo(styled(Stash)`
.ui--AddressMini {
vertical-align: middle;
}
@ -62,4 +60,4 @@ export default styled(Stash)`
cursor: default;
opacity: 0;
}
`;
`);

View File

@ -15,7 +15,7 @@ interface Props {
ids?: u64[];
}
export default function Summary ({ className = '', ids }: Props): React.ReactElement<Props> {
function Summary ({ className = '', ids }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
return (
@ -29,3 +29,5 @@ export default function Summary ({ className = '', ids }: Props): React.ReactEle
</SummaryBox>
);
}
export default React.memo(Summary);

View File

@ -18,7 +18,7 @@ interface Props {
ownStashes?: StakerState[];
}
export default function Bags ({ ownStashes }: Props): React.ReactElement<Props> {
function Bags ({ ownStashes }: Props): React.ReactElement<Props> {
const { t } = useTranslation();
const ids = useBagsIds();
const list = useBagsList(ids);
@ -39,7 +39,7 @@ export default function Bags ({ ownStashes }: Props): React.ReactElement<Props>
]);
const sorted = useMemo(
() => list
() => list && nodes
? [...list].sort((a, b) =>
nodes[a[0]]
? nodes[b[0]]
@ -57,7 +57,7 @@ export default function Bags ({ ownStashes }: Props): React.ReactElement<Props>
<>
<Summary ids={ids} />
<Table
empty={list && list.length === 0 && t<string>('No available bags')}
empty={nodes && list && list.length === 0 && t<string>('No available bags')}
emptySpinner={t<string>('Retrieving all available bags, this will take some time')}
header={headerRef.current}
>
@ -73,3 +73,5 @@ export default function Bags ({ ownStashes }: Props): React.ReactElement<Props>
</>
);
}
export default React.memo(Bags);

View File

@ -17,7 +17,7 @@ interface Result {
const EMPTY: [AccountId32 | null, Result] = [null, { isCompleted: false, list: [] }];
const EMPTY_LIST: AccountId32[] = [];
function useBagEntriesImpl (headId: AccountId32 | null, trigger: number): AccountId32[] {
function useBagEntriesImpl (headId: AccountId32 | null, trigger: number): [boolean, AccountId32[]] {
const { api } = useApi();
const [[currId, { isCompleted, list }], setCurrent] = useState<[AccountId32 | null, Result]>(EMPTY);
const node = useCall<Option<PalletBagsListListNode>>(!!currId && api.query.bagsList.listNodes, [currId]);
@ -45,9 +45,12 @@ function useBagEntriesImpl (headId: AccountId32 | null, trigger: number): Accoun
}
}, [node]);
return isCompleted
? list
: EMPTY_LIST;
return [
isCompleted,
isCompleted
? list
: EMPTY_LIST
];
}
export default createNamedHook('useBagEntries', useBagEntriesImpl);

View File

@ -5,12 +5,13 @@ import type { Option } from '@polkadot/types';
import type { PalletBagsListListNode } from '@polkadot/types/lookup';
import type { StashNode } from './types';
import { useEffect, useState } from 'react';
import { createNamedHook, useApi, useCall } from '@polkadot/react-hooks';
type Result = Record<string, StashNode[]>;
const multiOptions = {
defaultValue: {} as Result,
transform: (opts: Option<PalletBagsListListNode>[]): Result =>
opts
.filter((o) => o.isSome)
@ -28,10 +29,28 @@ const multiOptions = {
}, {})
};
function merge (prev: Result, curr: Result): Result {
return Object
.entries(curr)
.reduce((all: Result, [id, nodes]): Result => {
all[id] = prev[id] && JSON.stringify(nodes) === JSON.stringify(prev[id])
? prev[id]
: nodes;
return all;
}, {});
}
function useBagsNodesImpl (stashIds: string[]): Result {
const { api } = useApi();
const [result, setResult] = useState<Result>({});
const query = useCall(stashIds && stashIds.length !== 0 && api.query.bagsList.listNodes.multi, [stashIds], multiOptions);
return useCall(stashIds && stashIds.length !== 0 && api.query.bagsList.listNodes.multi, [stashIds], multiOptions) as Result;
useEffect((): void => {
query && setResult((prev) => merge(prev, query));
}, [query]);
return result;
}
export default createNamedHook('useBagsNodes', useBagsNodesImpl);