Skip to content

Commit 4ffcf30

Browse files
committed
[TOOL-3096] React SDK: Fix NFT components not including contract address in queryKey (#5966)
<!-- start pr-codex --> ## PR-Codex overview This PR focuses on improving the handling of NFT metadata in the `thirdweb` library by adding `contractAddress` to various query keys, which resolves issues with metadata caching when multiple contracts share the same token ID. ### Detailed summary - Added `contractAddress` to the query keys in `getQueryKey` functions for `NFTName`, `NFTMedia`, and `NFTDescription`. - Updated related queries to include `contractAddress`. - Fixed metadata display issues when rendering multiple contracts with the same token ID. - Enhanced tests in `name.test.tsx` and `media.test.tsx` to validate the new `contractAddress` parameter. > ✨ Ask PR-Codex anything about this PR by commenting with `/codex {your question}` <!-- end pr-codex -->
1 parent fe3f24e commit 4ffcf30

File tree

6 files changed

+72
-9
lines changed

6 files changed

+72
-9
lines changed

.changeset/rude-cats-clean.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"thirdweb": patch
3+
---
4+
5+
Fix NFT components not displaying correct metadata if multiple contracts with same token id is rendered because of incorrect caching

packages/thirdweb/src/react/web/ui/prebuilt/NFT/description.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ export function NFTDescription({
9595
queryKey: [
9696
"_internal_nft_description_",
9797
contract.chain.id,
98+
contract.address,
9899
tokenId.toString(),
99100
{
100101
resolver:

packages/thirdweb/src/react/web/ui/prebuilt/NFT/media.test.tsx

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import {
77
import { getFunctionId } from "../../../../../utils/function-id.js";
88
import { fetchNftMedia, getQueryKey } from "./media.js";
99

10+
const testContractAddress = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48";
11+
1012
describe.runIf(process.env.TW_SECRET_KEY)("NFTMedia", () => {
1113
it("fetchNftMedia should work with ERC721", async () => {
1214
const desc = await fetchNftMedia({
@@ -77,9 +79,16 @@ describe.runIf(process.env.TW_SECRET_KEY)("NFTMedia", () => {
7779
});
7880

7981
it("getQueryKey should work without mediaResolver", () => {
80-
expect(getQueryKey({ chainId: 1, tokenId: 1n })).toStrictEqual([
82+
expect(
83+
getQueryKey({
84+
chainId: 1,
85+
tokenId: 1n,
86+
contractAddress: testContractAddress,
87+
}),
88+
).toStrictEqual([
8189
"_internal_nft_media_",
8290
1,
91+
testContractAddress,
8392
"1",
8493
{
8594
resolver: undefined,
@@ -90,6 +99,7 @@ describe.runIf(process.env.TW_SECRET_KEY)("NFTMedia", () => {
9099
it("getQueryKey should work with mediaResolver being an object", () => {
91100
expect(
92101
getQueryKey({
102+
contractAddress: testContractAddress,
93103
chainId: 1,
94104
tokenId: 1n,
95105
mediaResolver: {
@@ -100,6 +110,7 @@ describe.runIf(process.env.TW_SECRET_KEY)("NFTMedia", () => {
100110
).toStrictEqual([
101111
"_internal_nft_media_",
102112
1,
113+
testContractAddress,
103114
"1",
104115
{
105116
resolver: {
@@ -119,12 +130,14 @@ describe.runIf(process.env.TW_SECRET_KEY)("NFTMedia", () => {
119130
expect(
120131
getQueryKey({
121132
chainId: 1,
133+
contractAddress: testContractAddress,
122134
tokenId: 1n,
123135
mediaResolver: fn,
124136
}),
125137
).toStrictEqual([
126138
"_internal_nft_media_",
127139
1,
140+
testContractAddress,
128141
"1",
129142
{
130143
resolver: fnId,

packages/thirdweb/src/react/web/ui/prebuilt/NFT/media.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ export function NFTMedia({
133133
const { contract, tokenId } = useNFTContext();
134134
const mediaQuery = useQuery({
135135
queryKey: getQueryKey({
136+
contractAddress: contract.address,
136137
chainId: contract.chain.id,
137138
tokenId,
138139
mediaResolver,
@@ -164,17 +165,19 @@ export function NFTMedia({
164165
* @internal
165166
*/
166167
export function getQueryKey(props: {
168+
contractAddress: string;
167169
chainId: number;
168170
tokenId: bigint;
169171
mediaResolver?:
170172
| NFTMediaInfo
171173
| (() => NFTMediaInfo)
172174
| (() => Promise<NFTMediaInfo>);
173175
}) {
174-
const { chainId, tokenId, mediaResolver } = props;
176+
const { chainId, tokenId, mediaResolver, contractAddress } = props;
175177
return [
176178
"_internal_nft_media_",
177179
chainId,
180+
contractAddress,
178181
tokenId.toString(),
179182
{
180183
resolver:

packages/thirdweb/src/react/web/ui/prebuilt/NFT/name.test.tsx

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import {
77
import { getFunctionId } from "../../../../../utils/function-id.js";
88
import { fetchNftName, getQueryKey } from "./name.js";
99

10+
const testContractAddress = "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48";
11+
1012
describe.runIf(process.env.TW_SECRET_KEY)("NFTName", () => {
1113
it("fetchNftName should work with ERC721", async () => {
1214
const desc = await fetchNftName({
@@ -61,26 +63,55 @@ describe.runIf(process.env.TW_SECRET_KEY)("NFTName", () => {
6163
});
6264

6365
it("getQueryKey should work without nameResolver", () => {
64-
expect(getQueryKey({ chainId: 1, tokenId: 1n })).toStrictEqual([
66+
expect(
67+
getQueryKey({
68+
chainId: 1,
69+
tokenId: 1n,
70+
contractAddress: testContractAddress,
71+
}),
72+
).toStrictEqual([
6573
"_internal_nft_name_",
6674
1,
75+
testContractAddress,
6776
"1",
6877
{ resolver: undefined },
6978
]);
7079
});
7180

7281
it("getQueryKey should work with nameResolver being a string", () => {
7382
expect(
74-
getQueryKey({ chainId: 1, tokenId: 1n, nameResolver: "test" }),
75-
).toStrictEqual(["_internal_nft_name_", 1, "1", { resolver: "test" }]);
83+
getQueryKey({
84+
chainId: 1,
85+
tokenId: 1n,
86+
nameResolver: "test",
87+
contractAddress: testContractAddress,
88+
}),
89+
).toStrictEqual([
90+
"_internal_nft_name_",
91+
1,
92+
testContractAddress,
93+
"1",
94+
{ resolver: "test" },
95+
]);
7696
});
7797

7898
it("getQueryKey should work with nameResolver being a () => string", () => {
7999
const fn = () => "test";
80100
const fnId = getFunctionId(fn);
81101
expect(
82-
getQueryKey({ chainId: 1, tokenId: 1n, nameResolver: fn }),
83-
).toStrictEqual(["_internal_nft_name_", 1, "1", { resolver: fnId }]);
102+
getQueryKey({
103+
chainId: 1,
104+
tokenId: 1n,
105+
nameResolver: fn,
106+
contractAddress: testContractAddress,
107+
}),
108+
).toStrictEqual([
109+
"_internal_nft_name_",
110+
1,
111+
testContractAddress,
112+
"1",
113+
{ resolver: fnId },
114+
]);
84115
});
85116

86117
it("getQueryKey should work with nameResolver being a async () => string", () => {
@@ -91,7 +122,14 @@ describe.runIf(process.env.TW_SECRET_KEY)("NFTName", () => {
91122
chainId: 1,
92123
tokenId: 1n,
93124
nameResolver: fn,
125+
contractAddress: testContractAddress,
94126
}),
95-
).toStrictEqual(["_internal_nft_name_", 1, "1", { resolver: fnId }]);
127+
).toStrictEqual([
128+
"_internal_nft_name_",
129+
1,
130+
testContractAddress,
131+
"1",
132+
{ resolver: fnId },
133+
]);
96134
});
97135
});

packages/thirdweb/src/react/web/ui/prebuilt/NFT/name.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ export function NFTName({
9595

9696
const nameQuery = useQuery({
9797
queryKey: getQueryKey({
98+
contractAddress: contract.address,
9899
chainId: contract.chain.id,
99100
tokenId,
100101
nameResolver,
@@ -118,14 +119,16 @@ export function NFTName({
118119
* @internal
119120
*/
120121
export function getQueryKey(props: {
122+
contractAddress: string;
121123
chainId: number;
122124
tokenId: bigint;
123125
nameResolver?: string | (() => string) | (() => Promise<string>);
124126
}) {
125-
const { chainId, tokenId, nameResolver } = props;
127+
const { chainId, tokenId, nameResolver, contractAddress } = props;
126128
return [
127129
"_internal_nft_name_",
128130
chainId,
131+
contractAddress,
129132
tokenId.toString(),
130133
{
131134
resolver:

0 commit comments

Comments
 (0)