From 55de58fd34e7df4ec1b140561d88764734c0edb4 Mon Sep 17 00:00:00 2001 From: Manuel Date: Thu, 22 Jun 2023 15:12:36 -0500 Subject: [PATCH] feat: improve home refresh logic (#202) ## Description Closes: #XXXX This PR improves the home refresh logic using a global flag that tells if the home should reload the data. This is a temporary workaround untill we have a proper application wide cache. --- ### Author Checklist *All items are required. Please add a note to the item if the item is not applicable and please add links to any relevant follow up issues.* - [x] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] provided a link to the relevant issue or specification - [x] reviewed "Files changed" and left comments if necessary - [x] confirmed all CI checks have passed ### Reviewers Checklist *All items are required. Please add a note if the item is not applicable and please add your handle next to the items reviewed if you only reviewed selected items.* - [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] confirmed all author checklist items have been addressed --- src/hooks/useOnScreenDetached.ts | 5 +++- src/recoil/home.ts | 23 +++++++++++++++++++ src/screens/BroadcastTx/index.tsx | 15 ++++++++++-- .../components/TransactionsListItem/index.tsx | 13 +++++++---- src/screens/Home/hooks.ts | 18 ++++++++------- src/screens/Home/index.tsx | 13 ++++++++++- src/screens/SettingsSwitchChain/index.tsx | 5 +++- 7 files changed, 75 insertions(+), 17 deletions(-) create mode 100644 src/recoil/home.ts diff --git a/src/hooks/useOnScreenDetached.ts b/src/hooks/useOnScreenDetached.ts index 0530e6dca..37339ee83 100644 --- a/src/hooks/useOnScreenDetached.ts +++ b/src/hooks/useOnScreenDetached.ts @@ -10,7 +10,10 @@ import useOnBackAction from './useOnBackAction'; const useOnScreenDetached = (onDetach: () => any, deps: DependencyList) => { const backActionStateRef = useRef(false); const isFocused = useIsFocused(); - const memoizedDetachCallback = useCallback(onDetach, [...deps, onDetach]); + // Safe to ignore the onDetach value since we want to memoize the provided + // onDetach function using the provided deps list. + // eslint-disable-next-line react-hooks/exhaustive-deps + const memoizedDetachCallback = useCallback(onDetach, [...deps]); useOnBackAction(() => { backActionStateRef.current = true; diff --git a/src/recoil/home.ts b/src/recoil/home.ts new file mode 100644 index 000000000..34b54a002 --- /dev/null +++ b/src/recoil/home.ts @@ -0,0 +1,23 @@ +import { atom, useRecoilValue, useSetRecoilState } from 'recoil'; + +/** + * Recoil that holds a boolean flag that tells if the home should + * be refreshed. + * NOTE: This is a workaround to force the home to refresh until we have + * a proper cache in place that can be updated after an operation that + * affect the data displayed in the Home screen. + */ +const homeShouldReloadData = atom({ + key: 'homeShouldReloadData', + default: false, +}); + +/** + * Hook that tels if the home should refresh the displayed data. + */ +export const useHomeShouldReloadData = () => useRecoilValue(homeShouldReloadData); + +/** + * Hook that provides a function to update the value of the refresh home flag. + */ +export const useSetHomeShouldReloadData = () => useSetRecoilState(homeShouldReloadData); diff --git a/src/screens/BroadcastTx/index.tsx b/src/screens/BroadcastTx/index.tsx index 6f6f5aef2..2b6e53db3 100644 --- a/src/screens/BroadcastTx/index.tsx +++ b/src/screens/BroadcastTx/index.tsx @@ -15,6 +15,7 @@ import { DPMImages } from 'types/images'; import { DeliverTxResponse } from '@desmoslabs/desmjs'; import useOnScreenDetached from 'hooks/useOnScreenDetached'; import { ImageSourcePropType } from 'react-native'; +import { useSetHomeShouldReloadData } from '@recoil/home'; import useStyles from './useStyles'; enum BroadcastStatus { @@ -77,6 +78,7 @@ const BroadcastTx: React.FC = (props) => { const [broadcastTxStatus, setBroadcastTxStatus] = useState({ status: BroadcastStatus.Cancel, }); + const setHomeShouldReloadData = useSetHomeShouldReloadData(); useEffect(() => { estimateFees(messages, memo); @@ -110,7 +112,7 @@ const BroadcastTx: React.FC = (props) => { } break; } - }, [broadcastTxStatus, onCancel, onError, onSuccess]); + }, [broadcastTxStatus, onCancel, onError, onSuccess, setHomeShouldReloadData]); const showSuccessModal = React.useCallback(() => { showModal(SingleButtonModal, { @@ -143,6 +145,7 @@ const BroadcastTx: React.FC = (props) => { const deliveredTx = broadcastResult.value; if (deliveredTx !== undefined) { setBroadcastTxStatus({ status: BroadcastStatus.Success, deliveredTx }); + setHomeShouldReloadData(true); showSuccessModal(); } else { setBroadcastTxStatus({ status: BroadcastStatus.Cancel }); @@ -154,7 +157,15 @@ const BroadcastTx: React.FC = (props) => { } setBroadcastingTx(false); } - }, [broadcastTx, estimatedFee, memo, messages, showErrorModal, showSuccessModal]); + }, [ + broadcastTx, + estimatedFee, + memo, + messages, + setHomeShouldReloadData, + showErrorModal, + showSuccessModal, + ]); return ( }> diff --git a/src/screens/Home/components/TransactionsListItem/index.tsx b/src/screens/Home/components/TransactionsListItem/index.tsx index 21c3bbe9e..82c23cafb 100644 --- a/src/screens/Home/components/TransactionsListItem/index.tsx +++ b/src/screens/Home/components/TransactionsListItem/index.tsx @@ -16,13 +16,18 @@ import useMessagesAmount from 'hooks/messages/useGetMessageAmount'; import useStyles from './useStyles'; export interface TransactionsListItemProps { + /** + * The transaction whose information will be displayed. + */ readonly transaction: Transaction; } -const TransactionsListItem = (props: TransactionsListItemProps) => { +/** + * Components that shows the information of a transaction. + */ +const TransactionsListItem: React.FC = ({ transaction }) => { const navigation = useNavigation>(); const { t } = useTranslation('transaction'); - const { transaction } = props; const styles = useStyles(); // -------- VARIABLES -------- @@ -35,14 +40,14 @@ const TransactionsListItem = (props: TransactionsListItemProps) => { // -------- CALLBACKS -------- - const onPress = useCallback(() => { + const onItemPress = useCallback(() => { navigation.navigate(ROUTES.TRANSACTION_DETAILS, { transaction, }); }, [navigation, transaction]); return ( - + {/* Header */} diff --git a/src/screens/Home/hooks.ts b/src/screens/Home/hooks.ts index d49690699..22de92881 100644 --- a/src/screens/Home/hooks.ts +++ b/src/screens/Home/hooks.ts @@ -1,25 +1,27 @@ -import { useLazyQuery } from '@apollo/client'; import GetTransactionsByAddress from 'services/graphql/queries/GetTransactionsByAddress'; import { useActiveAccountAddress } from '@recoil/activeAccount'; import React from 'react'; import { FetchDataFunction, usePaginatedData } from 'hooks/usePaginatedData'; import { GQLGetTransactionsByAddress, Transaction } from 'types/transactions'; import { convertGqlMessageToTransaction } from 'lib/GraphQLUtils/transaction'; +import { useApolloClient } from '@apollo/client'; /** * Hook that provides a {@link FetchDataFunction} for the {@link usePaginatedData} * hook to fetch the list of {@link Transaction} performed from the current active user. */ -const useFetchCurrentUserTransactions = () => { +const useFetchCurrentUserTransactions = (): FetchDataFunction => { + // Here we use useApolloClient instead of useLazyQuery + // to force the returned callback to change when the client instance changes + // so that the usePaginatedData hook can properly update the data. + const client = useApolloClient(); const activeAccountAddress = useActiveAccountAddress(); - const [fetchTransactions] = useLazyQuery(GetTransactionsByAddress, { - fetchPolicy: 'network-only', - }); - return React.useCallback>( async (offset, limit) => { - const { data, error } = await fetchTransactions({ + const { data, error } = await client.query({ + query: GetTransactionsByAddress, + fetchPolicy: 'network-only', variables: { addresses: `{${activeAccountAddress}}`, offset, @@ -39,7 +41,7 @@ const useFetchCurrentUserTransactions = () => { endReached: convertedData.length < limit, }; }, - [activeAccountAddress, fetchTransactions], + [activeAccountAddress, client], ); }; diff --git a/src/screens/Home/index.tsx b/src/screens/Home/index.tsx index f61b80d72..dec58210f 100644 --- a/src/screens/Home/index.tsx +++ b/src/screens/Home/index.tsx @@ -25,6 +25,7 @@ import { ListRenderItem } from '@shopify/flash-list/src/FlashListProps'; import { Transaction } from 'types/transactions'; import TransactionsListItem from 'screens/Home/components/TransactionsListItem'; import Spacer from 'components/Spacer'; +import { useHomeShouldReloadData, useSetHomeShouldReloadData } from '@recoil/home'; import { useActiveAccountTransactions } from './hooks'; import useStyles from './useStyles'; @@ -54,6 +55,9 @@ const Home: React.FC = (props) => { fetchMore: fetchMoreTransactions, } = useActiveAccountTransactions(); + const homeShouldReloadData = useHomeShouldReloadData(); + const setHomeShouldReloadData = useSetHomeShouldReloadData(); + // -------- REFS --------- const accountBalanceRef = useRef(); @@ -82,7 +86,14 @@ const Home: React.FC = (props) => { // ------- EFFECTS -------- - useFocusEffect(refreshData); + useFocusEffect( + React.useCallback(() => { + if (homeShouldReloadData) { + refreshData(); + setHomeShouldReloadData(false); + } + }, [homeShouldReloadData, refreshData, setHomeShouldReloadData]), + ); return ( diff --git a/src/screens/SettingsSwitchChain/index.tsx b/src/screens/SettingsSwitchChain/index.tsx index 427bf1c97..fbb897639 100644 --- a/src/screens/SettingsSwitchChain/index.tsx +++ b/src/screens/SettingsSwitchChain/index.tsx @@ -10,6 +10,7 @@ import Typography from 'components/Typography'; import Spacer from 'components/Spacer'; import { RootNavigatorParamList } from 'navigation/RootNavigator'; import ROUTES from 'navigation/routes'; +import { useSetHomeShouldReloadData } from '@recoil/home'; import useStyles from './useStyles'; type NavProps = StackScreenProps; @@ -20,12 +21,14 @@ const SettingsSwitchChain = (props: NavProps) => { const chainName = useSetting('chainName'); const setChainName = useSetSetting('chainName'); + const setHomeShouldReloadData = useSetHomeShouldReloadData(); const changeChain = React.useCallback( (newChainName: string) => { + setHomeShouldReloadData(true); setChainName(newChainName); }, - [setChainName], + [setChainName, setHomeShouldReloadData], ); const values: RadioValue[] = React.useMemo(