From aa7e2f6965517c3556f2dae64480ef12847a1b28 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Thu, 23 Mar 2023 16:22:15 -0500 Subject: [PATCH] Refactor hooks with useEntityRequest --- .../entity-store/hooks/useCreateEntity.ts | 17 ++++++----------- .../entity-store/hooks/useDeleteEntity.ts | 18 ++++++------------ app/soapbox/entity-store/hooks/useEntities.ts | 15 ++++++++------- app/soapbox/entity-store/hooks/useEntity.ts | 17 ++++++----------- 4 files changed, 26 insertions(+), 41 deletions(-) diff --git a/app/soapbox/entity-store/hooks/useCreateEntity.ts b/app/soapbox/entity-store/hooks/useCreateEntity.ts index 87625f942..658cb180d 100644 --- a/app/soapbox/entity-store/hooks/useCreateEntity.ts +++ b/app/soapbox/entity-store/hooks/useCreateEntity.ts @@ -1,10 +1,10 @@ -import { useState } from 'react'; import { z } from 'zod'; -import { useApi, useAppDispatch } from 'soapbox/hooks'; +import { useAppDispatch } from 'soapbox/hooks'; import { importEntities } from '../actions'; +import { useEntityRequest } from './useEntityRequest'; import { parseEntitiesPath, toAxiosRequest } from './utils'; import type { Entity } from '../types'; @@ -16,21 +16,18 @@ interface UseCreateEntityOpts { function useCreateEntity( expandedPath: ExpandedEntitiesPath, - request: EntityRequest, + entityRequest: EntityRequest, opts: UseCreateEntityOpts = {}, ) { - const api = useApi(); const dispatch = useAppDispatch(); - const [isLoading, setIsLoading] = useState(false); + const { request, isLoading } = useEntityRequest(); const { entityType, listKey } = parseEntitiesPath(expandedPath); async function createEntity(data: Data, callbacks: EntityCallbacks = {}): Promise { - setIsLoading(true); - try { - const result = await api.request({ - ...toAxiosRequest(request), + const result = await request({ + ...toAxiosRequest(entityRequest), data, }); @@ -48,8 +45,6 @@ function useCreateEntity( callbacks.onError(error); } } - - setIsLoading(false); } return { diff --git a/app/soapbox/entity-store/hooks/useDeleteEntity.ts b/app/soapbox/entity-store/hooks/useDeleteEntity.ts index 718ca5e11..a8c671cc1 100644 --- a/app/soapbox/entity-store/hooks/useDeleteEntity.ts +++ b/app/soapbox/entity-store/hooks/useDeleteEntity.ts @@ -1,9 +1,8 @@ -import { useState } from 'react'; - -import { useApi, useAppDispatch, useGetState } from 'soapbox/hooks'; +import { useAppDispatch, useGetState } from 'soapbox/hooks'; import { deleteEntities, importEntities } from '../actions'; +import { useEntityRequest } from './useEntityRequest'; import { toAxiosRequest } from './utils'; import type { EntityCallbacks, EntityRequest } from './types'; @@ -15,16 +14,13 @@ import type { EntityCallbacks, EntityRequest } from './types'; */ function useDeleteEntity( entityType: string, - request: EntityRequest, + entityRequest: EntityRequest, ) { - const api = useApi(); const dispatch = useAppDispatch(); const getState = useGetState(); - const [isLoading, setIsLoading] = useState(false); + const { request, isLoading } = useEntityRequest(); async function deleteEntity(entityId: string, callbacks: EntityCallbacks = {}): Promise { - setIsLoading(true); - // Get the entity before deleting, so we can reverse the action if the API request fails. const entity = getState().entities[entityType]?.store[entityId]; @@ -33,10 +29,10 @@ function useDeleteEntity( try { // HACK: replace occurrences of `:id` in the URL. Maybe there's a better way? - const axiosReq = toAxiosRequest(request); + const axiosReq = toAxiosRequest(entityRequest); axiosReq.url?.replaceAll(':id', entityId); - await api.request(axiosReq); + await request(axiosReq); // Success - finish deleting entity from the state. dispatch(deleteEntities([entityId], entityType)); @@ -54,8 +50,6 @@ function useDeleteEntity( callbacks.onError(e); } } - - setIsLoading(false); } return { diff --git a/app/soapbox/entity-store/hooks/useEntities.ts b/app/soapbox/entity-store/hooks/useEntities.ts index b424ed1f6..c20d75f43 100644 --- a/app/soapbox/entity-store/hooks/useEntities.ts +++ b/app/soapbox/entity-store/hooks/useEntities.ts @@ -2,13 +2,14 @@ import { useEffect } from 'react'; import z from 'zod'; import { getNextLink, getPrevLink } from 'soapbox/api'; -import { useApi, useAppDispatch, useAppSelector, useGetState } from 'soapbox/hooks'; +import { useAppDispatch, useAppSelector, useGetState } from 'soapbox/hooks'; import { filteredArray } from 'soapbox/schemas/utils'; import { realNumberSchema } from 'soapbox/utils/numbers'; import { entitiesFetchFail, entitiesFetchRequest, entitiesFetchSuccess, invalidateEntityList } from '../actions'; -import { parseEntitiesPath, toAxiosRequest } from './utils'; +import { useEntityRequest } from './useEntityRequest'; +import { parseEntitiesPath } from './utils'; import type { Entity, EntityListState } from '../types'; import type { EntitiesPath, EntityRequest, EntitySchema, ExpandedEntitiesPath } from './types'; @@ -32,11 +33,11 @@ function useEntities( /** Tells us where to find/store the entity in the cache. */ expandedPath: ExpandedEntitiesPath, /** API route to GET, eg `'/api/v1/notifications'`. If undefined, nothing will be fetched. */ - request: EntityRequest, + entityRequest: EntityRequest, /** Additional options for the hook. */ opts: UseEntitiesOpts = {}, ) { - const api = useApi(); + const { request } = useEntityRequest(); const dispatch = useAppDispatch(); const getState = useGetState(); @@ -61,7 +62,7 @@ function useEntities( dispatch(entitiesFetchRequest(entityType, listKey)); try { - const response = await api.request(toAxiosRequest(req)); + const response = await request(req); const schema = opts.schema || z.custom(); const entities = filteredArray(schema).parse(response.data); const parsedCount = realNumberSchema.safeParse(response.headers['x-total-count']); @@ -82,7 +83,7 @@ function useEntities( }; const fetchEntities = async(): Promise => { - await fetchPage(request, true); + await fetchPage(entityRequest, true); }; const fetchNextPage = async(): Promise => { @@ -112,7 +113,7 @@ function useEntities( if (isInvalid || isUnset || isStale) { fetchEntities(); } - }, [request, isEnabled]); + }, [entityRequest, isEnabled]); return { entities, diff --git a/app/soapbox/entity-store/hooks/useEntity.ts b/app/soapbox/entity-store/hooks/useEntity.ts index cb71b86a9..1b091c655 100644 --- a/app/soapbox/entity-store/hooks/useEntity.ts +++ b/app/soapbox/entity-store/hooks/useEntity.ts @@ -1,11 +1,11 @@ -import { useEffect, useState } from 'react'; +import { useEffect } from 'react'; import z from 'zod'; -import { useApi, useAppDispatch, useAppSelector } from 'soapbox/hooks'; +import { useAppDispatch, useAppSelector } from 'soapbox/hooks'; import { importEntities } from '../actions'; -import { toAxiosRequest } from './utils'; +import { useEntityRequest } from './useEntityRequest'; import type { Entity } from '../types'; import type { EntitySchema, EntityPath, EntityRequest } from './types'; @@ -20,10 +20,10 @@ interface UseEntityOpts { function useEntity( path: EntityPath, - request: EntityRequest, + entityRequest: EntityRequest, opts: UseEntityOpts = {}, ) { - const api = useApi(); + const { request, isLoading: isFetching } = useEntityRequest(); const dispatch = useAppDispatch(); const [entityType, entityId] = path; @@ -33,21 +33,16 @@ function useEntity( const entity = useAppSelector(state => state.entities[entityType]?.store[entityId] as TEntity | undefined); - const [isFetching, setIsFetching] = useState(false); const isLoading = isFetching && !entity; const fetchEntity = async () => { - setIsFetching(true); - try { - const response = await api.request(toAxiosRequest(request)); + const response = await request(entityRequest); const entity = schema.parse(response.data); dispatch(importEntities([entity], entityType)); } catch (e) { // do nothing } - - setIsFetching(false); }; useEffect(() => {