Skip to content

Commit 862ad56

Browse files
jlobue10claude
andcommitted
React to gateway option changes without a remount
Enabling 'Fetch IPFS content through a gateway' had no effect on NFTs already on screen: useNFTVerifyHash never re-ran (nothing depended on the preference), and a failed ipfs metadata fetch stayed cached in the NFT provider, so those NFTs kept looking broken until a full app reload (Bugbot, PR Chia-Network#3029). - Both verification effects in useNFTVerifyHash now list the preference as a dependency, so flipping it re-checks data and preview URIs immediately. - useMetadataData retries cached metadata failures when the preference flips - only failures: successfully fetched metadata is hash-verified content and unaffected by how it was fetched. The retry goes through invalidate, whose refetch notifies mounted subscribers. The cache layer needs no matching change: gateway-disabled fetch refusals are never persisted, so the re-run's fresh requests go through cleanly. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017NXWAjaHb9SFafLeguTHd8
1 parent c755e0c commit 862ad56

2 files changed

Lines changed: 34 additions & 3 deletions

File tree

packages/gui/src/components/nfts/provider/hooks/useMetadataData.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@ import { EventEmitter } from 'events';
22

33
import { type NFTInfo } from '@chia-network/api';
44
import debug from 'debug';
5-
import { useState, useCallback, useMemo } from 'react';
5+
import { useState, useCallback, useEffect, useMemo, useRef } from 'react';
66

77
import type Metadata from '../../../../@types/Metadata';
88
import type MetadataOnDemand from '../../../../@types/MetadataOnDemand';
99
import type MetadataState from '../../../../@types/MetadataState';
1010
import useFetchAndProcessMetadata from '../../../../hooks/useFetchAndProcessMetadata';
11+
import useIpfsGateway from '../../../../hooks/useIpfsGateway';
1112
import getNFTId from '../../../../util/getNFTId';
1213

1314
const log = debug('chia-gui:NFTProvider:useMetadataData');
@@ -159,6 +160,30 @@ export default function useMetadataData(props: UseMetadataDataProps) {
159160
[getMetadata /* immutable */, metadatasOnDemand /* immutable */],
160161
);
161162

163+
const [ipfsGateway] = useIpfsGateway();
164+
const lastIpfsGatewayRef = useRef(ipfsGateway);
165+
166+
useEffect(() => {
167+
if (lastIpfsGatewayRef.current === ipfsGateway) {
168+
return;
169+
}
170+
lastIpfsGatewayRef.current = ipfsGateway;
171+
172+
// Flipping the gateway option changes which URIs the main process will
173+
// fetch, so cached failures are stale — without this, a failed ipfs
174+
// metadata fetch stayed cached here and its NFT kept looking broken
175+
// after enabling the option, until a full app reload. Only failures are
176+
// retried: successfully fetched metadata is hash-verified content and
177+
// unaffected by how it was fetched.
178+
metadatasOnDemand.forEach((metadataOnDemand, nftId) => {
179+
if (metadataOnDemand.error) {
180+
invalidate(nftId).catch((e) => {
181+
log(`Error retrying metadata for nftId: ${nftId}`, e);
182+
});
183+
}
184+
});
185+
}, [ipfsGateway, invalidate /* immutable */, metadatasOnDemand /* immutable */]);
186+
162187
// immutable function
163188
const subscribeToMetadataChanges = useCallback(
164189
(id: string | undefined, callback: (nftState: MetadataState) => void) => {

packages/gui/src/hooks/useNFTVerifyHash.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import compareChecksums from '../util/compareChecksums';
77

88
import selectNFTPreviewState, { type NFTPreviewState } from './selectNFTPreviewState';
99
import useCache from './useCache';
10+
import useIpfsGateway from './useIpfsGateway';
1011
import useNFT from './useNFT';
1112
import useNFTMetadata from './useNFTMetadata';
1213

@@ -21,6 +22,11 @@ export default function useNFTVerifyHash(nftId?: string, options: UseNFTVerifyHa
2122
const { preview = false, ignoreSizeLimit = false } = options;
2223

2324
const { getChecksum } = useCache();
25+
// Not read directly: the value changes which URIs the main process will
26+
// fetch at all, so both verification effects list it as a dependency and
27+
// re-run when the user flips the option — without this, NFTs already on
28+
// screen would keep their failed state until a remount.
29+
const [ipfsGateway] = useIpfsGateway();
2430

2531
const { nft, isLoading: isLoadingNFT, error: errorNFT } = useNFT(nftId);
2632
const { isLoading: isLoadingMetadata, metadata, error: errorMetadata } = useNFTMetadata(nftId);
@@ -201,7 +207,7 @@ export default function useNFTVerifyHash(nftId?: string, options: UseNFTVerifyHa
201207
dataGeneration.current += 1;
202208
}
203209
};
204-
}, [nft, isLoadingNFT, validateData]);
210+
}, [nft, isLoadingNFT, validateData, ipfsGateway]);
205211

206212
useEffect(() => {
207213
const generation = previewGeneration.current + 1;
@@ -227,7 +233,7 @@ export default function useNFTVerifyHash(nftId?: string, options: UseNFTVerifyHa
227233
previewGeneration.current += 1;
228234
}
229235
};
230-
}, [preview, nft, metadata, isLoadingNFT, isLoadingMetadata, validatePreview]);
236+
}, [preview, nft, metadata, isLoadingNFT, isLoadingMetadata, validatePreview, ipfsGateway]);
231237

232238
const previewState = useMemo(
233239
() =>

0 commit comments

Comments
 (0)