From ef2fa26126dab170e6ee77b8e41f787c684fd125 Mon Sep 17 00:00:00 2001 From: Keith Grant Date: Thu, 30 Jan 2020 16:13:19 -0800 Subject: [PATCH] rename useFetch to useRequest --- awx/ui_next/src/api/index.js | 2 + awx/ui_next/src/api/useRequest.js | 38 +++++++++ .../InventoryDetail/InventoryDetail.jsx | 16 +--- .../Inventory/InventoryDetail/useEndpoint.js | 79 ------------------- .../OrganizationList/OrganizationList.jsx | 40 ++-------- 5 files changed, 48 insertions(+), 127 deletions(-) create mode 100644 awx/ui_next/src/api/useRequest.js delete mode 100644 awx/ui_next/src/screens/Inventory/InventoryDetail/useEndpoint.js diff --git a/awx/ui_next/src/api/index.js b/awx/ui_next/src/api/index.js index f9acea4211..2fd939ea69 100644 --- a/awx/ui_next/src/api/index.js +++ b/awx/ui_next/src/api/index.js @@ -24,6 +24,7 @@ import UnifiedJobs from './models/UnifiedJobs'; import Users from './models/Users'; import WorkflowJobs from './models/WorkflowJobs'; import WorkflowJobTemplates from './models/WorkflowJobTemplates'; +import useRequest from './useRequest'; const AdHocCommandsAPI = new AdHocCommands(); const ConfigAPI = new Config(); @@ -79,4 +80,5 @@ export { UsersAPI, WorkflowJobsAPI, WorkflowJobTemplatesAPI, + useRequest, }; diff --git a/awx/ui_next/src/api/useRequest.js b/awx/ui_next/src/api/useRequest.js new file mode 100644 index 0000000000..909dfda683 --- /dev/null +++ b/awx/ui_next/src/api/useRequest.js @@ -0,0 +1,38 @@ +import { useEffect, useState, useRef, useCallback } from 'react'; + +export default function useRequest(makeRequest, initialValue) { + const [result, setResult] = useState(initialValue); + const [error, setError] = useState(null); + const [isLoading, setIsLoading] = useState(false); + const isMounted = useRef(null); + + useEffect(() => { + isMounted.current = true; + return () => { + isMounted.current = false; + }; + }, []); + + return { + result, + error, + isLoading, + request: useCallback(async () => { + setIsLoading(true); + try { + const response = await makeRequest(); + if (isMounted.current) { + setResult(response); + } + } catch (err) { + if (isMounted.current) { + setError(err); + } + } finally { + if (isMounted.current) { + setIsLoading(false); + } + } + }, [makeRequest]), + }; +} diff --git a/awx/ui_next/src/screens/Inventory/InventoryDetail/InventoryDetail.jsx b/awx/ui_next/src/screens/Inventory/InventoryDetail/InventoryDetail.jsx index d7cca7727a..c48057f648 100644 --- a/awx/ui_next/src/screens/Inventory/InventoryDetail/InventoryDetail.jsx +++ b/awx/ui_next/src/screens/Inventory/InventoryDetail/InventoryDetail.jsx @@ -10,28 +10,18 @@ import { VariablesDetail } from '@components/CodeMirrorInput'; import DeleteButton from '@components/DeleteButton'; import ContentError from '@components/ContentError'; import ContentLoading from '@components/ContentLoading'; -import { InventoriesAPI } from '@api'; -import useEndpoint, { useFetch } from './useEndpoint'; +import { InventoriesAPI, useRequest } from '@api'; import { Inventory } from '../../../types'; function InventoryDetail({ inventory, i18n }) { const history = useHistory(); - // initial approach with useEndpoint() - // const { results: instanceGroups, isLoading, error } = useEndpoint( - // useCallback(async () => { - // const { data } = await InventoriesAPI.readInstanceGroups(inventory.id); - // return data.results; - // }, [inventory.id]) - // ); - - // more versatile approach with useFetch() const { result: instanceGroups, isLoading, error, - fetch: fetchInstanceGroups, - } = useFetch( + request: fetchInstanceGroups, + } = useRequest( useCallback(async () => { const { data } = await InventoriesAPI.readInstanceGroups(inventory.id); return data.results; diff --git a/awx/ui_next/src/screens/Inventory/InventoryDetail/useEndpoint.js b/awx/ui_next/src/screens/Inventory/InventoryDetail/useEndpoint.js deleted file mode 100644 index 4ace382a1a..0000000000 --- a/awx/ui_next/src/screens/Inventory/InventoryDetail/useEndpoint.js +++ /dev/null @@ -1,79 +0,0 @@ -import { useEffect, useState, useRef, useCallback } from 'react'; - -// Initial approach (useEffect baked in) -export default function useEndpoint(fetch) { - const [results, setResults] = useState([]); - const [error, setError] = useState(null); - const [isLoading, setIsLoading] = useState(true); - const isMounted = useRef(null); - - useEffect(() => { - isMounted.current = true; - (async () => { - // Do we want this set here or not? Can result in extra - // unmounting/re-mounting of child components - setIsLoading(true); - try { - const fetchedResults = await fetch(); - if (isMounted.current) { - setResults(fetchedResults); - } - } catch (err) { - if (isMounted.current) { - setError(err); - } - } finally { - if (isMounted.current) { - setIsLoading(false); - } - } - })(); - return () => { - isMounted.current = false; - }; - }, [fetch]); - - return { - results, - isLoading, - error, - }; -} - -// more versatile approach (returns function to make API request) -export function useFetch(fetch, initialValue) { - const [result, setResult] = useState(initialValue); - const [error, setError] = useState(null); - const [isLoading, setIsLoading] = useState(false); - const isMounted = useRef(null); - - useEffect(() => { - isMounted.current = true; - return () => { - isMounted.current = false; - }; - }, []); - - return { - result, - error, - isLoading, - fetch: useCallback(async () => { - setIsLoading(true); - try { - const response = await fetch(); - if (isMounted.current) { - setResult(response); - } - } catch (err) { - if (isMounted.current) { - setError(err); - } - } finally { - if (isMounted.current) { - setIsLoading(false); - } - } - }, [fetch]), - }; -} diff --git a/awx/ui_next/src/screens/Organization/OrganizationList/OrganizationList.jsx b/awx/ui_next/src/screens/Organization/OrganizationList/OrganizationList.jsx index 6abe157d03..3f571d9a55 100644 --- a/awx/ui_next/src/screens/Organization/OrganizationList/OrganizationList.jsx +++ b/awx/ui_next/src/screens/Organization/OrganizationList/OrganizationList.jsx @@ -4,7 +4,7 @@ import { withI18n } from '@lingui/react'; import { t } from '@lingui/macro'; import { Card, PageSection } from '@patternfly/react-core'; -import { OrganizationsAPI } from '@api'; +import { OrganizationsAPI, useRequest } from '@api'; import AlertModal from '@components/AlertModal'; import DataListToolbar from '@components/DataListToolbar'; import ErrorDetail from '@components/ErrorDetail'; @@ -13,10 +13,6 @@ import PaginatedDataList, { ToolbarDeleteButton, } from '@components/PaginatedDataList'; import { getQSConfig, parseQueryString } from '@util/qs'; -// TODO: move useEndpoint to better location -import useEndpoint, { - useFetch, -} from '../../Inventory/InventoryDetail/useEndpoint'; import OrganizationListItem from './OrganizationListItem'; @@ -35,38 +31,12 @@ function OrganizationsList({ i18n }) { const addUrl = `${match.url}/add`; - // const { - // results: organizations, - // error: contentError, - // isLoading: isOrgsLoading, - // } = useEndpoint( - // useCallback(async () => { - // const params = parseQueryString(QS_CONFIG, location.search); - // const [ - // { - // data: { count, results }, - // }, - // { - // data: { actions }, - // }, - // ] = await Promise.all([ - // OrganizationsAPI.read(params), - // loadOrganizationActions(), - // ]); - // return { - // organizations: results, - // count, - // actions, - // }; - // }, [location]) - // ); - const { result: { organizations = {}, organizationCount, actions }, error: contentError, isLoading: isOrgsLoading, - fetch: fetchOrganizations, - } = useFetch( + request: fetchOrganizations, + } = useRequest( useCallback(async () => { const params = parseQueryString(QS_CONFIG, location.search); const [orgs, orgActions] = await Promise.all([ @@ -89,8 +59,8 @@ function OrganizationsList({ i18n }) { const { isLoading: isDeleteLoading, // error: deletionError, - fetch: deleteOrganizations, - } = useFetch( + request: deleteOrganizations, + } = useRequest( useCallback(async () => { return Promise.all( selected.map(({ id }) => OrganizationsAPI.destroy(id))