React cache Function Not Deduplicating Calls - Function Executed Every Time
Unanswered
Highlander posted this in #help-forum
HighlanderOP
I am using React’s
I added
context.ts:
cache
function from "react"
to memoize several asynchronous or synchronous functions in my Next.js project. However, I am experiencing an issue where the cached functions are executed every time they are called, instead of being deduplicated and cached properly.I added
console.log
statements inside the cached functions to verify if they are being called multiple times, and the logs confirm that the functions run on every invocation regardless of identical input parameters.context.ts:
export const dedupedParamsCache = cache(() => {
console.log("dedupedParamsCache called");
return createSearchParamsCache({
categoryName: parseAsString.withDefault(""),
categoryId: parseAsString.withDefault("")
});
});
export const dedupedGetSearchParamsCache = cache(
(priceRange: { minPrice: number; maxPrice: number }) => {
console.log("dedupedGetSearchParamsCache called");
return getSearchParamsCache(priceRange);
}
);
export const dedupedGetCategory = cache((input: GetCategorySchema) => {
console.log("dedupedGetCategory called");
return getCategory(input);
});
export const dedupedGetCategoryProductVariantsPriceRange = cache(
(input: GetCategoryProductVariantsPriceRangeSchema) => {
console.log("dedupedGetCategoryProductVariantsPriceRange called");
return getCategoryProductVariantsPriceRange(input);
}
);
export const dedupedGetCategoryProductFilters = cache(
(input: GetCategoryProductFiltersSchema) => {
console.log("dedupedGetCategoryProductFilters called");
return getCategoryProductFilters(input);
}
);
2 Replies
HighlanderOP
layout.tsx:
export type CategoryLayoutProps = {
filters: React.ReactNode;
products: React.ReactNode;
};
export default function CategoryLayout({
filters,
products
}: CategoryLayoutProps): React.JSX.Element {
return (
<TransitionProvider>
<section className="container py-4">
<div className="items-start grid gap-4 lg:grid-cols-4">
{filters}
{products}
</div>
</section>
</TransitionProvider>
);
}
@filters:
@products:
const paramsCache = dedupedParamsCache();
export default async function FiltersPage({
params,
searchParams
}: NextPageProps): Promise<React.JSX.Element> {
const { categoryId } = await paramsCache.parse(params);
if (!categoryId) {
return notFound();
}
const priceRange = await dedupedGetCategoryProductVariantsPriceRange({
categoryId
});
const parsedSearchParams = await dedupedGetSearchParamsCache({
minPrice: priceRange.minPrice,
maxPrice: priceRange.maxPrice
}).parse(searchParams);
const productFilters = await dedupedGetCategoryProductFilters({
categoryId,
...parsedSearchParams
});
return (
<CategoryFiltersCard
priceRange={priceRange}
productFilters={productFilters}
/>
);
}
@products:
const paramsCache = dedupedParamsCache();
export default async function ProductsPage({
params,
searchParams
}: NextPageProps): Promise<React.JSX.Element> {
const { categoryId } = await paramsCache.parse(params);
if (!categoryId) {
return notFound();
}
const [category, priceRange] = await Promise.all([
dedupedGetCategory({ id: categoryId }),
dedupedGetCategoryProductVariantsPriceRange({ categoryId })
]);
if (!category) {
return notFound();
}
const parsedSearchParams = await dedupedGetSearchParamsCache({
minPrice: priceRange.minPrice,
maxPrice: priceRange.maxPrice
}).parse(searchParams);
const [variantsData, productFilters] = await Promise.all([
getCategoryFilteredProductVariants({
categoryId,
...parsedSearchParams
}),
dedupedGetCategoryProductFilters({
categoryId,
...parsedSearchParams
})
]);
return (
<CategoryProducts
category={category}
variantsData={variantsData}
priceRange={priceRange}
productFilters={productFilters}
/>
);
}