feat: call update with null data from useDataProvider hook on variables change (#2689)

This commit is contained in:
Bartłomiej Głownia 2023-01-24 15:01:51 +01:00 committed by GitHub
parent 31881f8e5a
commit 0cff5895c7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 80 additions and 58 deletions

View File

@ -1,3 +1,3 @@
import { Market } from './market'; import { MarketPage } from './market';
export default Market; export default MarketPage;

View File

@ -5,6 +5,7 @@ import {
t, t,
titlefy, titlefy,
useDataProvider, useDataProvider,
useThrottledDataProvider,
} from '@vegaprotocol/react-helpers'; } from '@vegaprotocol/react-helpers';
import { AsyncRenderer, Splash } from '@vegaprotocol/ui-toolkit'; import { AsyncRenderer, Splash } from '@vegaprotocol/ui-toolkit';
import type { import type {
@ -31,7 +32,47 @@ export interface SingleMarketData extends SingleMarketFieldsFragment {
data: MarketData; data: MarketData;
} }
export const Market = () => { const TitleUpdater = ({
marketId,
marketName,
decimalPlaces,
}: {
marketId?: string;
marketName?: string;
decimalPlaces?: number;
}) => {
const pageTitle = usePageTitleStore((store) => store.pageTitle);
const updateTitle = usePageTitleStore((store) => store.updateTitle);
const { data: marketData } = useThrottledDataProvider<
MarketData,
MarketDataUpdateFieldsFragment
>(
{
dataProvider: marketDataProvider,
variables: useMemo(() => ({ marketId }), [marketId]),
skip: !marketId,
},
1000
);
useEffect(() => {
const marketPrice = calculatePrice(marketData?.markPrice, decimalPlaces);
if (marketName) {
const newPageTitle = titlefy([marketName, marketPrice]);
if (pageTitle !== newPageTitle) {
updateTitle(newPageTitle);
}
}
}, [
decimalPlaces,
marketName,
marketData?.markPrice,
pageTitle,
updateTitle,
]);
return null;
};
export const MarketPage = () => {
const { marketId } = useParams(); const { marketId } = useParams();
const navigate = useNavigate(); const navigate = useNavigate();
@ -39,9 +80,6 @@ export const Market = () => {
const update = useGlobalStore((store) => store.update); const update = useGlobalStore((store) => store.update);
const lastMarketId = useGlobalStore((store) => store.marketId); const lastMarketId = useGlobalStore((store) => store.marketId);
const pageTitle = usePageTitleStore((store) => store.pageTitle);
const updateTitle = usePageTitleStore((store) => store.updateTitle);
const onSelect = useCallback( const onSelect = useCallback(
(id: string) => { (id: string) => {
if (id && id !== marketId) { if (id && id !== marketId) {
@ -51,56 +89,20 @@ export const Market = () => {
[marketId, navigate] [marketId, navigate]
); );
const variables = useMemo(
() => ({
marketId: marketId || '',
}),
[marketId]
);
const updateMarketId = useCallback(
({ data }: { data: { id?: string } | null }) => {
if (data?.id && data.id !== lastMarketId) {
update({ marketId: data.id });
}
return true;
},
[update, lastMarketId]
);
const { data, error, loading } = useDataProvider< const { data, error, loading } = useDataProvider<
SingleMarketFieldsFragment, SingleMarketFieldsFragment,
never never
>({ >({
dataProvider: marketProvider, dataProvider: marketProvider,
variables, variables: useMemo(() => ({ marketId: marketId || '' }), [marketId]),
update: updateMarketId,
skip: !marketId, skip: !marketId,
}); });
const marketName = data?.tradableInstrument.instrument.name; useEffect(() => {
const updateProvider = useCallback( if (data?.id && data.id !== lastMarketId) {
({ data: marketData }: { data: MarketData | null }) => { update({ marketId: data.id });
const marketPrice = calculatePrice(
marketData?.markPrice,
data?.decimalPlaces
);
if (marketName) {
const newPageTitle = titlefy([marketName, marketPrice]);
if (pageTitle !== newPageTitle) {
updateTitle(newPageTitle);
} }
} }, [update, lastMarketId, data?.id]);
return true;
},
[updateTitle, pageTitle, marketName, data?.decimalPlaces]
);
useDataProvider<MarketData, MarketDataUpdateFieldsFragment>({
dataProvider: marketDataProvider,
update: updateProvider,
variables,
skip: !marketId || !data,
});
const tradeView = useMemo(() => { const tradeView = useMemo(() => {
if (w > 960) { if (w > 960) {
@ -123,6 +125,11 @@ export const Market = () => {
data={data || undefined} data={data || undefined}
noDataCondition={(data) => false} noDataCondition={(data) => false}
> >
<TitleUpdater
marketId={data?.id}
marketName={data?.tradableInstrument.instrument.name}
decimalPlaces={data?.decimalPlaces}
/>
{tradeView} {tradeView}
</AsyncRenderer> </AsyncRenderer>
); );

View File

@ -17,15 +17,11 @@ export const useAccountBalance = (assetId?: string) => {
const account = assetId const account = assetId
? getSettlementAccount({ accounts: data, assetId }) ? getSettlementAccount({ accounts: data, assetId })
: undefined; : undefined;
if (accountBalance !== account?.balance) {
setAccountBalance(account?.balance || ''); setAccountBalance(account?.balance || '');
}
if (accountDecimals !== account?.asset.decimals) {
setAccountDecimals(account?.asset.decimals || null); setAccountDecimals(account?.asset.decimals || null);
}
return true; return true;
}, },
[accountBalance, accountDecimals, assetId] [assetId]
); );
useDataProvider({ useDataProvider({

View File

@ -161,6 +161,13 @@ describe('useDataProvider hook', () => {
}); });
expect(update).toBeCalledTimes(1); expect(update).toBeCalledTimes(1);
// setting same variables, with different object reference
await act(async () => {
rerender({ dataProvider, update, variables: { ...variables } });
});
expect(unsubscribe).toBeCalledTimes(0);
expect(dataProvider).toBeCalledTimes(1);
// changing variables after date was loaded // changing variables after date was loaded
await act(async () => { await act(async () => {
rerender({ dataProvider, update, variables: { partyId: '0x321' } }); rerender({ dataProvider, update, variables: { partyId: '0x321' } });
@ -173,7 +180,7 @@ describe('useDataProvider hook', () => {
await act(async () => { await act(async () => {
callback({ ...updateCallbackPayload }); callback({ ...updateCallbackPayload });
}); });
expect(update).toBeCalledTimes(2); expect(update).toBeCalledTimes(3);
// changing variables, apollo query will return error // changing variables, apollo query will return error
await act(async () => { await act(async () => {
@ -193,7 +200,7 @@ describe('useDataProvider hook', () => {
pageInfo: null, pageInfo: null,
}); });
}); });
expect(update).toBeCalledTimes(3); expect(update).toBeCalledTimes(5);
}); });
it('do not create data provider instance when skip is true', async () => { it('do not create data provider instance when skip is true', async () => {

View File

@ -1,6 +1,8 @@
import { useState, useEffect, useRef, useCallback } from 'react'; import { useState, useEffect, useRef, useCallback } from 'react';
import throttle from 'lodash/throttle'; import throttle from 'lodash/throttle';
import isEqual from 'lodash/isEqual';
import { useApolloClient } from '@apollo/client'; import { useApolloClient } from '@apollo/client';
import { usePrevious } from './use-previous';
import type { OperationVariables } from '@apollo/client'; import type { OperationVariables } from '@apollo/client';
import type { import type {
Subscribe, Subscribe,
@ -52,9 +54,9 @@ export const useDataProvider = <
dataProvider, dataProvider,
update, update,
insert, insert,
variables,
skipUpdates, skipUpdates,
skip, skip,
...props
}: useDataProviderParams<Data, Delta, Variables>) => { }: useDataProviderParams<Data, Delta, Variables>) => {
const client = useApolloClient(); const client = useApolloClient();
const [data, setData] = useState<Data | null>(null); const [data, setData] = useState<Data | null>(null);
@ -65,6 +67,13 @@ export const useDataProvider = <
const reloadRef = useRef<((force?: boolean) => void) | undefined>(undefined); const reloadRef = useRef<((force?: boolean) => void) | undefined>(undefined);
const loadRef = useRef<Load<Data> | undefined>(undefined); const loadRef = useRef<Load<Data> | undefined>(undefined);
const initialized = useRef<boolean>(false); const initialized = useRef<boolean>(false);
const prevVariables = usePrevious(props.variables);
const [variables, setVariables] = useState(props.variables);
useEffect(() => {
if (!isEqual(prevVariables, props.variables)) {
setVariables(props.variables);
}
}, [props.variables, prevVariables]);
const flush = useCallback(() => { const flush = useCallback(() => {
if (flushRef.current) { if (flushRef.current) {
flushRef.current(); flushRef.current();
@ -125,6 +134,9 @@ export const useDataProvider = <
setData(null); setData(null);
setError(undefined); setError(undefined);
setTotalCount(undefined); setTotalCount(undefined);
if (initialized.current && update) {
update({ data: null });
}
initialized.current = false; initialized.current = false;
if (skip) { if (skip) {
setLoading(false); setLoading(false);