Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

migrate to ReactQuery v5 #1321

Merged
merged 4 commits into from
Nov 2, 2023
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
change signature of hooks
  • Loading branch information
tom2drum committed Nov 1, 2023
commit 0f26de3084ced1a370c3635d8059114218965d19
2 changes: 2 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -20,6 +20,7 @@ module.exports = {
'plugin:@typescript-eslint/recommended',
'plugin:jest/recommended',
'plugin:playwright/playwright-test',
'plugin:@tanstack/eslint-plugin-query/recommended',
],
plugins: [
'es5',
@@ -31,6 +32,7 @@ module.exports = {
'eslint-plugin-import-helpers',
'jest',
'eslint-plugin-no-cyrillic-string',
'@tanstack/query',
],
parser: '@typescript-eslint/parser',
parserOptions: {
11 changes: 7 additions & 4 deletions lib/api/useApiQuery.tsx
Original file line number Diff line number Diff line change
@@ -23,12 +23,15 @@ export default function useApiQuery<R extends ResourceName, E = unknown>(
) {
const apiFetch = useApiFetch();

return useQuery<ResourcePayload<R>, ResourceError<E>, ResourcePayload<R>>(
getResourceKey(resource, { pathParams, queryParams }),
async() => {
return useQuery<ResourcePayload<R>, ResourceError<E>, ResourcePayload<R>>({
// eslint-disable-next-line @tanstack/query/exhaustive-deps
queryKey: getResourceKey(resource, { pathParams, queryParams }),
queryFn: async() => {
// all errors and error typing is handled by react-query
// so error response will never go to the data
// that's why we are safe here to do type conversion "as Promise<ResourcePayload<R>>"
return apiFetch(resource, { pathParams, queryParams, fetchParams }) as Promise<ResourcePayload<R>>;
}, queryOptions);
},
...queryOptions,
});
}
38 changes: 20 additions & 18 deletions lib/hooks/useGetCsrfToken.tsx
Original file line number Diff line number Diff line change
@@ -10,27 +10,29 @@ import useFetch from 'lib/hooks/useFetch';
export default function useGetCsrfToken() {
const nodeApiFetch = useFetch();

useQuery(getResourceKey('csrf'), async() => {
if (!isNeedProxy()) {
const url = buildUrl('csrf');
const apiResponse = await fetch(url, { credentials: 'include' });
const csrfFromHeader = apiResponse.headers.get('x-bs-account-csrf');
useQuery({
queryKey: getResourceKey('csrf'),
queryFn: async() => {
if (!isNeedProxy()) {
const url = buildUrl('csrf');
const apiResponse = await fetch(url, { credentials: 'include' });
const csrfFromHeader = apiResponse.headers.get('x-bs-account-csrf');

if (!csrfFromHeader) {
Sentry.captureException(new Error('Client fetch failed'), { tags: {
source: 'fetch',
'source.resource': 'csrf',
'status.code': 500,
'status.text': 'Unable to obtain csrf token from header',
} });
return;
}
if (!csrfFromHeader) {
Sentry.captureException(new Error('Client fetch failed'), { tags: {
source: 'fetch',
'source.resource': 'csrf',
'status.code': 500,
'status.text': 'Unable to obtain csrf token from header',
} });
return;
}

return { token: csrfFromHeader };
}
return { token: csrfFromHeader };
}

return nodeApiFetch('/node-api/csrf');
}, {
return nodeApiFetch('/node-api/csrf');
},
enabled: Boolean(cookies.get(cookies.NAMES.API_TOKEN)),
});
}
14 changes: 6 additions & 8 deletions lib/hooks/useIsSafeAddress.tsx
Original file line number Diff line number Diff line change
@@ -8,20 +8,18 @@ const feature = config.features.safe;
export default function useIsSafeAddress(hash: string | undefined): boolean {
const fetch = useFetch();

const { data } = useQuery(
[ 'safe_transaction_api', hash ],
async() => {
const { data } = useQuery({
queryKey: [ 'safe_transaction_api', hash ],
queryFn: async() => {
if (!feature.isEnabled || !hash) {
return Promise.reject();
}

return fetch(`${ feature.apiUrl }/${ hash }`, undefined, { omitSentryErrorLog: true });
},
{
enabled: feature.isEnabled && Boolean(hash),
refetchOnMount: false,
},
);
enabled: feature.isEnabled && Boolean(hash),
refetchOnMount: false,
});

return Boolean(data);
}
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -39,8 +39,8 @@
"@monaco-editor/react": "^4.4.6",
"@sentry/react": "^7.72.0",
"@slise/embed-react": "^2.2.0",
"@tanstack/react-query": "^4.0.10",
"@tanstack/react-query-devtools": "^4.0.10",
"@tanstack/react-query": "^5.4.3",
"@tanstack/react-query-devtools": "^5.4.3",
"@types/papaparse": "^5.3.5",
"@types/react-scroll": "^1.8.4",
"@web3modal/ethereum": "^2.6.2",
@@ -89,6 +89,7 @@
"@playwright/experimental-ct-react": "1.35.1",
"@playwright/test": "^1.35.1",
"@svgr/webpack": "^6.5.1",
"@tanstack/eslint-plugin-query": "^5.0.5",
"@testing-library/react": "^14.0.0",
"@total-typescript/ts-reset": "^0.4.0",
"@types/crypto-js": "^4.1.1",
5 changes: 3 additions & 2 deletions ui/apiKey/ApiKeyModal/ApiKeyForm.tsx
Original file line number Diff line number Diff line change
@@ -57,7 +57,8 @@ const ApiKeyForm: React.FC<Props> = ({ data, onClose, setAlertVisible }) => {
});
};

const mutation = useMutation(updateApiKey, {
const mutation = useMutation({
mutationFn: updateApiKey,
onSuccess: async(data) => {
const response = data as unknown as ApiKey;

@@ -148,7 +149,7 @@ const ApiKeyForm: React.FC<Props> = ({ data, onClose, setAlertVisible }) => {
size="lg"
type="submit"
isDisabled={ !isDirty }
isLoading={ mutation.isLoading }
isLoading={ mutation.isPending }
>
{ data ? 'Save' : 'Generate API key' }
</Button>
5 changes: 3 additions & 2 deletions ui/customAbi/CustomAbiModal/CustomAbiForm.tsx
Original file line number Diff line number Diff line change
@@ -63,7 +63,8 @@ const CustomAbiForm: React.FC<Props> = ({ data, onClose, setAlertVisible }) => {

const formBackgroundColor = useColorModeValue('white', 'gray.900');

const mutation = useMutation(customAbiKey, {
const mutation = useMutation({
mutationFn: customAbiKey,
onSuccess: (data) => {
const response = data as unknown as CustomAbi;
queryClient.setQueryData([ resourceKey('custom_abi') ], (prevData: CustomAbis | undefined) => {
@@ -175,7 +176,7 @@ const CustomAbiForm: React.FC<Props> = ({ data, onClose, setAlertVisible }) => {
size="lg"
type="submit"
isDisabled={ !isDirty }
isLoading={ mutation.isLoading }
isLoading={ mutation.isPending }
>
{ data ? 'Save' : 'Create custom ABI' }
</Button>
17 changes: 8 additions & 9 deletions ui/marketplace/useMarketplaceApps.tsx
Original file line number Diff line number Diff line change
@@ -24,15 +24,14 @@ function isAppCategoryMatches(category: string, app: MarketplaceAppOverview, fav

export default function useMarketplaceApps(filter: string, selectedCategoryId: string = MarketplaceCategory.ALL, favoriteApps: Array<string> = []) {
const apiFetch = useApiFetch();
const { isPlaceholderData, isError, error, data } = useQuery<unknown, ResourceError<unknown>, Array<MarketplaceAppOverview>>(
[ 'marketplace-apps' ],
async() => apiFetch(configUrl, undefined, { resource: 'marketplace-apps' }),
{
select: (data) => (data as Array<MarketplaceAppOverview>).sort((a, b) => a.title.localeCompare(b.title)),
placeholderData: feature.isEnabled ? Array(9).fill(MARKETPLACE_APP) : undefined,
staleTime: Infinity,
enabled: feature.isEnabled,
});
const { isPlaceholderData, isError, error, data } = useQuery<unknown, ResourceError<unknown>, Array<MarketplaceAppOverview>>({
queryKey: [ 'marketplace-apps' ],
queryFn: async() => apiFetch(configUrl, undefined, { resource: 'marketplace-apps' }),
select: (data) => (data as Array<MarketplaceAppOverview>).sort((a, b) => a.title.localeCompare(b.title)),
placeholderData: feature.isEnabled ? Array(9).fill(MARKETPLACE_APP) : undefined,
staleTime: Infinity,
enabled: feature.isEnabled,
});

const displayedApps = React.useMemo(() => {
return data?.filter(app => isAppNameMatches(filter, app) && isAppCategoryMatches(selectedCategoryId, app, favoriteApps)) || [];
16 changes: 7 additions & 9 deletions ui/pages/MarketplaceApp.tsx
Original file line number Diff line number Diff line change
@@ -34,9 +34,9 @@ const MarketplaceApp = () => {
const router = useRouter();
const id = getQueryParamString(router.query.id);

const { isLoading, isError, error, data } = useQuery<unknown, ResourceError<unknown>, MarketplaceAppOverview>(
[ 'marketplace-apps', id ],
async() => {
const { isPending, isError, error, data } = useQuery<unknown, ResourceError<unknown>, MarketplaceAppOverview>({
queryKey: [ 'marketplace-apps', id ],
queryFn: async() => {
const result = await apiFetch<Array<MarketplaceAppOverview>, unknown>(configUrl, undefined, { resource: 'marketplace-apps' });
if (!Array.isArray(result)) {
throw result;
@@ -49,12 +49,10 @@ const MarketplaceApp = () => {

return item;
},
{
enabled: feature.isEnabled,
},
);
enabled: feature.isEnabled,
});

const [ isFrameLoading, setIsFrameLoading ] = useState(isLoading);
const [ isFrameLoading, setIsFrameLoading ] = useState(isPending);
const { colorMode } = useColorMode();

const handleIframeLoad = useCallback(() => {
@@ -106,7 +104,7 @@ const MarketplaceApp = () => {

return (
<>
{ !isLoading && <PageTitle title={ data.title } backLink={ backLink }/> }
{ !isPending && <PageTitle title={ data.title } backLink={ backLink }/> }
<Center
h="100vh"
mx={{ base: -4, lg: -12 }}
29 changes: 15 additions & 14 deletions ui/privateTags/AddressModal/AddressForm.tsx
Original file line number Diff line number Diff line change
@@ -44,22 +44,23 @@ const AddressForm: React.FC<Props> = ({ data, onClose, onSuccess, setAlertVisibl

const formBackgroundColor = useColorModeValue('white', 'gray.900');

const { mutate } = useMutation((formData: Inputs) => {
const body = {
name: formData?.tag,
address_hash: formData?.address,
};
const { mutate } = useMutation({
mutationFn: (formData: Inputs) => {
const body = {
name: formData?.tag,
address_hash: formData?.address,
};

const isEdit = data?.id;
if (isEdit) {
return apiFetch('private_tags_address', {
pathParams: { id: data.id },
fetchParams: { method: 'PUT', body },
});
}
const isEdit = data?.id;
if (isEdit) {
return apiFetch('private_tags_address', {
pathParams: { id: data.id },
fetchParams: { method: 'PUT', body },
});
}

return apiFetch('private_tags_address', { fetchParams: { method: 'POST', body } });
}, {
return apiFetch('private_tags_address', { fetchParams: { method: 'POST', body } });
},
onError: (error: ResourceErrorAccount<AddressTagErrors>) => {
setPending(false);
const errorMap = error.payload?.errors;
35 changes: 18 additions & 17 deletions ui/privateTags/TransactionModal/TransactionForm.tsx
Original file line number Diff line number Diff line change
@@ -47,22 +47,23 @@ const TransactionForm: React.FC<Props> = ({ data, onClose, onSuccess, setAlertVi
const queryClient = useQueryClient();
const apiFetch = useApiFetch();

const { mutate } = useMutation((formData: Inputs) => {
const body = {
name: formData?.tag,
transaction_hash: formData?.transaction,
};
const isEdit = data?.id;

if (isEdit) {
return apiFetch('private_tags_tx', {
pathParams: { id: data.id },
fetchParams: { method: 'PUT', body },
});
}

return apiFetch('private_tags_tx', { fetchParams: { method: 'POST', body } });
}, {
const { mutate } = useMutation({
mutationFn: (formData: Inputs) => {
const body = {
name: formData?.tag,
transaction_hash: formData?.transaction,
};
const isEdit = data?.id;

if (isEdit) {
return apiFetch('private_tags_tx', {
pathParams: { id: data.id },
fetchParams: { method: 'PUT', body },
});
}

return apiFetch('private_tags_tx', { fetchParams: { method: 'POST', body } });
},
onError: (error: ResourceErrorAccount<TransactionTagErrors>) => {
setPending(false);
const errorMap = error.payload?.errors;
@@ -76,7 +77,7 @@ const TransactionForm: React.FC<Props> = ({ data, onClose, onSuccess, setAlertVi
}
},
onSuccess: async() => {
await queryClient.refetchQueries([ resourceKey('private_tags_tx') ]);
await queryClient.refetchQueries({ queryKey: [ resourceKey('private_tags_tx') ] });
await onSuccess();
onClose();
setPending(false);
5 changes: 3 additions & 2 deletions ui/publicTags/PublicTagsForm/PublicTagsForm.tsx
Original file line number Diff line number Diff line change
@@ -109,7 +109,8 @@ const PublicTagsForm = ({ changeToDataScreen, data }: Props) => {
});
};

const mutation = useMutation(updatePublicTag, {
const mutation = useMutation({
mutationFn: updatePublicTag,
onSuccess: async(data) => {
const response = data as unknown as PublicTag;

@@ -237,7 +238,7 @@ const PublicTagsForm = ({ changeToDataScreen, data }: Props) => {
size="lg"
type="submit"
isDisabled={ !isDirty }
isLoading={ mutation.isLoading }
isLoading={ mutation.isPending }
>
Send request
</Button>
5 changes: 3 additions & 2 deletions ui/shared/DeleteModal.tsx
Original file line number Diff line number Diff line change
@@ -39,7 +39,8 @@ const DeleteModal: React.FC<Props> = ({
onClose();
}, [ onClose, setAlertVisible ]);

const mutation = useMutation(mutationFn, {
const mutation = useMutation({
mutationFn,
onSuccess: async() => {
onSuccess();
onClose();
@@ -70,7 +71,7 @@ const DeleteModal: React.FC<Props> = ({
<Button
size="lg"
onClick={ onDeleteClick }
isLoading={ mutation.isLoading }
isLoading={ mutation.isPending }
// FIXME: chackra's button is disabled when isLoading
isDisabled={ false }
>
13 changes: 6 additions & 7 deletions ui/shared/nft/useNftMediaType.tsx
Original file line number Diff line number Diff line change
@@ -13,9 +13,9 @@ export default function useNftMediaType(url: string | null, isEnabled: boolean)

const fetch = useFetch();

const { data } = useQuery<unknown, ResourceError<unknown>, MediaType>(
[ 'nft-media-type', url ],
async() => {
const { data } = useQuery<unknown, ResourceError<unknown>, MediaType>({
queryKey: [ 'nft-media-type', url ],
queryFn: async() => {
if (!url) {
return 'image';
}
@@ -41,10 +41,9 @@ export default function useNftMediaType(url: string | null, isEnabled: boolean)
return 'image';
}
},
{
enabled: isEnabled && Boolean(url),
staleTime: Infinity,
});
enabled: isEnabled && Boolean(url),
staleTime: Infinity,
});

return data;
}
Loading