Skip to content

Commit 8e8af15

Browse files
perf: skip RecentPostsWidget fetch when its rail is hidden on mobile (#1024)
1 parent 616b229 commit 8e8af15

4 files changed

Lines changed: 34 additions & 24 deletions

File tree

src/components/LibraryLayout.tsx

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { GithubIcon } from '~/components/icons/GithubIcon'
44
import { DiscordIcon } from '~/components/icons/DiscordIcon'
55
import { Link, useMatches, useParams } from '@tanstack/react-router'
66
import { useLocalStorage } from '~/utils/useLocalStorage'
7+
import { useMediaQuery } from '~/utils/useMediaQuery'
78
import { useClickOutside } from '~/hooks/useClickOutside'
89
import { last } from '~/utils/utils'
910
import type { ConfigSchema, MenuItem } from '~/utils/config'
@@ -424,26 +425,6 @@ function clampProgress(value: number) {
424425
return Math.min(Math.max(value, 0), 1)
425426
}
426427

427-
function useMediaQuery(query: string) {
428-
const [matches, setMatches] = React.useState(false)
429-
430-
React.useEffect(() => {
431-
const mediaQueryList = window.matchMedia(query)
432-
const updateMatches = () => {
433-
setMatches(mediaQueryList.matches)
434-
}
435-
436-
updateMatches()
437-
mediaQueryList.addEventListener('change', updateMatches)
438-
439-
return () => {
440-
mediaQueryList.removeEventListener('change', updateMatches)
441-
}
442-
}, [query])
443-
444-
return matches
445-
}
446-
447428
function areDocsPartnerSlotsEqual(
448429
left: DocsPartnerScrollSlot | undefined,
449430
right: DocsPartnerScrollSlot | undefined,
@@ -903,6 +884,7 @@ export function LibraryLayout({
903884
surface: 'docs_rail',
904885
})
905886
const shouldShowDocsPartnerSlot = useMediaQuery('(max-width: 767.98px)')
887+
const isDesktopViewport = useMediaQuery('(min-width: 768px)')
906888

907889
const groupInitialOpenState = React.useMemo(() => {
908890
return visibleMenuConfig.reduce<Record<string, boolean>>(
@@ -1431,7 +1413,7 @@ export function LibraryLayout({
14311413
partners={activePartners}
14321414
/>
14331415
<div className="hidden md:block border border-gray-500/20 rounded-l-lg overflow-hidden w-full">
1434-
<RecentPostsWidget />
1416+
<RecentPostsWidget enabled={isDesktopViewport} />
14351417
</div>
14361418
</RightRail>
14371419
)}

src/components/RecentPostsWidget.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import { formatPublishedDate } from '~/utils/blog'
55

66
type RecentPostsWidgetProps = {
77
posts?: ReadonlyArray<RecentPost>
8+
/** Set to false to skip the client fetch when the widget is rendered but not visible (e.g. hidden below a CSS breakpoint). Ignored when `posts` is provided. */
9+
enabled?: boolean
810
}
911

1012
function RecentPostsList({ posts }: { posts: ReadonlyArray<RecentPost> }) {
@@ -63,11 +65,14 @@ function RecentPostsSkeleton() {
6365
)
6466
}
6567

66-
export function RecentPostsWidget({ posts }: RecentPostsWidgetProps) {
68+
export function RecentPostsWidget({
69+
posts,
70+
enabled = true,
71+
}: RecentPostsWidgetProps) {
6772
const recentPostsQuery = useQuery({
6873
queryKey: ['recentPosts'],
6974
queryFn: () => fetchRecentPosts(),
70-
enabled: posts === undefined,
75+
enabled: posts === undefined && enabled,
7176
staleTime: 1000 * 60 * 5,
7277
})
7378

src/routes/blog.$.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { LibrariesWidget } from '~/components/LibrariesWidget'
99
import { partners } from '~/utils/partners'
1010
import { PartnersRail, RightRail } from '~/components/RightRail'
1111
import { RecentPostsWidget } from '~/components/RecentPostsWidget'
12+
import { useMediaQuery } from '~/utils/useMediaQuery'
1213

1314
import { Toc } from '~/components/Toc'
1415
import { Breadcrumbs } from '~/components/Breadcrumbs'
@@ -76,6 +77,7 @@ function BlogPost() {
7677
const headings = markdown.headings
7778

7879
const isTocVisible = headings.length > 1
80+
const isDesktopViewport = useMediaQuery('(min-width: 768px)')
7981

8082
const markdownContainerRef = React.useRef<HTMLDivElement>(null)
8183
const [activeHeadings, setActiveHeadings] = React.useState<Array<string>>([])
@@ -203,7 +205,7 @@ function BlogPost() {
203205
partners={activePartners}
204206
/>
205207
<div className="hidden md:block border border-gray-500/20 rounded-l-lg overflow-hidden w-full">
206-
<RecentPostsWidget />
208+
<RecentPostsWidget enabled={isDesktopViewport} />
207209
</div>
208210
<Card>
209211
<LibrariesWidget />

src/utils/useMediaQuery.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import * as React from 'react'
2+
3+
export function useMediaQuery(query: string) {
4+
const [matches, setMatches] = React.useState(false)
5+
6+
React.useEffect(() => {
7+
const mediaQueryList = window.matchMedia(query)
8+
const updateMatches = () => {
9+
setMatches(mediaQueryList.matches)
10+
}
11+
12+
updateMatches()
13+
mediaQueryList.addEventListener('change', updateMatches)
14+
15+
return () => {
16+
mediaQueryList.removeEventListener('change', updateMatches)
17+
}
18+
}, [query])
19+
20+
return matches
21+
}

0 commit comments

Comments
 (0)