Skip to content

Commit

Permalink
Merge pull request #179 from apollographql/query-preloader
Browse files Browse the repository at this point in the history
Add query preloading to artist and album routes
  • Loading branch information
jerelmiller authored Feb 15, 2024
2 parents 5d51b7b + e49db9b commit 78ef09c
Showing 5 changed files with 66 additions and 21 deletions.
7 changes: 6 additions & 1 deletion client/src/apollo/client.ts
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@ import {
InMemoryCache,
ApolloLink,
createHttpLink,
createQueryPreloader,
from,
split,
} from '@apollo/client';
@@ -72,7 +73,7 @@ const httpLink = createHttpLink({
uri: import.meta.env.VITE_SERVER_HOST,
});

export default new ApolloClient({
const client = new ApolloClient({
link: from([httpAuthLink, persistedQueries, httpLink]),
connectToDevTools: true,
name: 'Spotify Showcase Website',
@@ -170,3 +171,7 @@ export default new ApolloClient({
},
}),
});

export const preloadQuery = createQueryPreloader(client);

export default client;
14 changes: 12 additions & 2 deletions client/src/components/LoggedInLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ReactNode, useRef } from 'react';
import { Outlet } from 'react-router-dom';
import { Outlet, useNavigation } from 'react-router-dom';
import Layout from './Layout';
import ScrollContainerContext from './ScrollContainerContext';
import Playbar, { LoadingState as PlaybarLoadingState } from './Playbar';
@@ -21,16 +21,26 @@ import CurrentUserMenu, {
import Suspense from './Suspense';
import StandardLoadingState from './StandardLoadingState';
import { withHighlight } from './LoadingStateHighlighter';
import cx from 'classnames';

const LoggedInLayout = () => {
const navigation = useNavigation();

return (
<Suspense fallback={<LoadingState />}>
<Container>
<Sidebar />
<Main>
<Header />
<Suspense fallback={<StandardLoadingState />}>
<Outlet />
<div
className={cx({
'opacity-30 transition-opacity duration-100':
navigation.state === 'loading',
})}
>
<Outlet />
</div>
</Suspense>
</Main>
<Playbar />
2 changes: 2 additions & 0 deletions client/src/router.tsx
Original file line number Diff line number Diff line change
@@ -87,6 +87,7 @@ const routes = createRoutesFromElements(
/>
<Route
path="albums/:albumId"
loader={AlbumRoute.loader}
element={
<Suspense fallback={<AlbumRoute.LoadingState />}>
<AlbumRoute.RouteComponent />
@@ -95,6 +96,7 @@ const routes = createRoutesFromElements(
/>
<Route
path="artists/:artistId"
loader={ArtistRoute.loader}
element={
<Suspense fallback={<ArtistRoute.LoadingState />}>
<ArtistRoute.RouteComponent />
34 changes: 26 additions & 8 deletions client/src/routes/albums/album.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { gql, useSuspenseQuery } from '@apollo/client';
import { useParams } from 'react-router-dom';
import {
TypedDocumentNode,
gql,
useReadQuery,
useSuspenseQuery,
} from '@apollo/client';
import { LoaderFunctionArgs, useLoaderData, useParams } from 'react-router-dom';
import {
AlbumRouteQuery,
AlbumRouteQueryVariables,
@@ -22,8 +27,12 @@ import useSavedTracksContains from '../../hooks/useSavedTracksContains';
import LikeButton from '../../components/LikeButton';
import useSaveAlbumsMutation from '../../mutations/useSaveAlbumsMutation';
import useRemoveSavedAlbumsMutation from '../../mutations/useRemoveSavedAlbumsMutation';
import { preloadQuery } from '../../apollo/client';

const ALBUM_ROUTE_QUERY = gql`
const ALBUM_ROUTE_QUERY: TypedDocumentNode<
AlbumRouteQuery,
AlbumRouteQueryVariables
> = gql`
query AlbumRouteQuery($albumId: ID!) {
me {
albumsContains(ids: [$albumId])
@@ -65,12 +74,21 @@ const PLAYBACK_STATE_FRAGMENT = gql`
}
`;

export const loader = ({ params }: LoaderFunctionArgs) => {
const { albumId } = params;

if (!albumId) {
throw new Response('', { status: 404 });
}

return preloadQuery(ALBUM_ROUTE_QUERY, {
variables: { albumId },
}).toPromise();
};

export const RouteComponent = () => {
const { albumId } = useParams() as { albumId: 'string' };
const { data } = useSuspenseQuery<AlbumRouteQuery, AlbumRouteQueryVariables>(
ALBUM_ROUTE_QUERY,
{ variables: { albumId } }
);
const queryRef = useLoaderData() as Awaited<ReturnType<typeof loader>>;
const { data } = useReadQuery(queryRef);

const [resumePlayback] = useResumePlaybackMutation();
const [saveAlbums] = useSaveAlbumsMutation();
30 changes: 20 additions & 10 deletions client/src/routes/artists/artist.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { gql, useSuspenseQuery } from '@apollo/client';
import { TypedDocumentNode, gql, useReadQuery } from '@apollo/client';
import cx from 'classnames';
import { useParams } from 'react-router-dom';
import { LoaderFunctionArgs, useLoaderData } from 'react-router-dom';
import { Get } from 'type-fest';
import { ArtistRouteQuery, ArtistRouteQueryVariables } from '../../types/api';
import AlbumTile from '../../components/AlbumTile';
@@ -9,10 +9,14 @@ import ArtistTopTracks from '../../components/ArtistTopTracks';
import Page from '../../components/Page';
import Skeleton from '../../components/Skeleton';
import TileGrid from '../../components/TileGrid';
import { preloadQuery } from '../../apollo/client';

type Album = NonNullable<Get<ArtistRouteQuery, 'artist.albums.edges[0].node'>>;

const ARTIST_ROUTE_QUERY = gql`
const ARTIST_ROUTE_QUERY: TypedDocumentNode<
ArtistRouteQuery,
ArtistRouteQueryVariables
> = gql`
query ArtistRouteQuery($artistId: ID!) {
artist(id: $artistId) {
id
@@ -74,15 +78,21 @@ const classNames = {
section: 'flex flex-col gap-2',
};

export const RouteComponent = () => {
const { artistId } = useParams() as { artistId: string };
export const loader = ({ params }: LoaderFunctionArgs) => {
const { artistId } = params;

if (!artistId) {
throw new Response('', { status: 404 });
}

const { data } = useSuspenseQuery<
ArtistRouteQuery,
ArtistRouteQueryVariables
>(ARTIST_ROUTE_QUERY, {
return preloadQuery(ARTIST_ROUTE_QUERY, {
variables: { artistId },
});
}).toPromise();
};

export const RouteComponent = () => {
const queryRef = useLoaderData() as Awaited<ReturnType<typeof loader>>;
const { data } = useReadQuery(queryRef);

const artist = data.artist;

0 comments on commit 78ef09c

Please sign in to comment.