spotify-react-query
v1.0.0
Published
React Query hooks for the Spotify Web API
Maintainers
Readme
Spotify React Query
Lightweight React Query hooks for the Spotify Web API. Built on TanStack Query v5, requests for Spotify resources are automatically cached and deduped. Under the hood, dataloader batches related requests to keep API quota usage low.
Used in production by musictaste.space.
Requirements
- React
>= 18 @tanstack/react-query^5- Node
>= 18(or any modern browser/edge runtime — uses nativefetch)
Install
npm install spotify-react-query @tanstack/react-query
# or
pnpm add spotify-react-query @tanstack/react-query
# or
yarn add spotify-react-query @tanstack/react-queryUsage
To use the hooks, wrap dependent components in a SpotifyQueryProvider and pass in:
- A React Query
QueryClient. - A Spotify client that satisfies the
SpotifyClientinterface exported from this package.
spotify-react-query ships a tiny dependency-free createSpotifyClient built on the native fetch API — recommended for browser, edge, and modern Node runtimes. You can also bring your own implementation (e.g. spotify-web-api-node); any object whose method shapes match SpotifyClient is accepted.
The library will not issue requests until getAccessToken() returns a value, so you can safely mount the provider before your token resolves. Token refreshes are managed by your application outside the provider.
SpotifyQueryProvider (recommended: built-in fetch client)
import { QueryClient } from "@tanstack/react-query"
import { SpotifyQueryProvider, createSpotifyClient } from "spotify-react-query"
const query = new QueryClient()
// Bring your own access-token state (Redux, Zustand, context, etc.).
let accessToken: string | undefined
const spotify = createSpotifyClient({
getAccessToken: () => accessToken,
})
const App = () => {
return (
<SpotifyQueryProvider query={query} spotify={spotify}>
<DependentComponents />
</SpotifyQueryProvider>
)
}Using spotify-web-api-node instead
If you already use spotify-web-api-node, pass it directly — it satisfies the SpotifyClient interface structurally:
import SpotifyWebApi from "spotify-web-api-node"
import { SpotifyQueryProvider } from "spotify-react-query"
const spotify = new SpotifyWebApi()
spotify.setAccessToken("<ACCESS_TOKEN>")
<SpotifyQueryProvider query={query} spotify={spotify}>{/* ... */}</SpotifyQueryProvider>Migrating from
<= 0.12.x:
spotify-web-api-nodeis no longer a peer dependency. Switch tocreateSpotifyClient(built-in, nativefetch) to drop it and its Node-only transitive deps from your bundle. If you specifically need its full SDK, install it explicitly.- This release targets
@tanstack/react-queryv5. Upgrade your app following the TanStack v5 migration guide — most notably,useQuery(["key"], fn, opts)is no longer accepted; useuseQuery({ queryKey, queryFn, ... }). The hooks exported by this package already use the v5 form, so no consumer code change is required.
Quickstart Example
import { useSimplifiedTrack } from "spotify-react-query"
function TrackComponent({ id }: { id: string }) {
const { data: track, isLoading } = useSimplifiedTrack(id)
if (isLoading) return <div>Loading...</div>
if (!track) return null
return (
<div>
{track.name} by {track.artists[0].name}
</div>
)
}Simplified and Full Entities
For many Spotify API entities, there are two subtypes which are returned depending on your query - simplified and full. Please refer to the Spotify API documentation to differentiate between the two given the entity. In the majority of cases, the simplified result may be enough.
Under the hood, when a query fetches simplified data about related entities (eg. when you query for an album and it returns simplified artist and album tracks), the library will prime the cache with those entities. This means that if you first used the useFullAlbum hook to fetch an album, and then use a component leveraging the useSimplifiedTrack hook to render the tracks based on the album track URIs, the data will already be in the cache and an additional network request will not be made.
For this reason, it's recommended that you use the simplified entities wherever possible.
Hooks
Tracks
function useSimplifiedTrack(id: string, options?: ReactQueryOptions)function useFullTrack(id: string, options?: ReactQueryOptions)function useFullTracks(ids: string[], options?: ReactQueryOptions)Albums
function useSimplifiedAlbum(id: string, options?: ReactQueryOptions)function useFullAlbum(id: string, options?: ReactQueryOptions)Artists
function useSimplifiedArtist(id: string, options?: ReactQueryOptions)function useFullArtist(id: string, options?: ReactQueryOptions)function useFullArtists(ids: string[], options?: ReactQueryOptions)Playlists
function usePlaylist(id: string, options?: ReactQueryOptions)function usePlaylistTracks({
variables?: { id: string; fields?: string; limit?: number; offset?: number; market?: string } },
options?: ReactQueryOptions
)Statistics
function useUserTopTracks(
variables: { limit?: number; offset?: number; time_range: "short_term" | "medium_term" | "long_term" },
options?: ReactQueryOptions
)function useUserTopArtists(
variables: { limit?: number; offset?: number; time_range: "short_term" | "medium_term" | "long_term" },
options?: ReactQueryOptions
)function useRecentlyPlayedTracks(
variables: { after?: number; before?: number; limit?: number },
options?: ReactQueryOptions
)Spotify Client
You can access the underlying Spotify client from any component inside the provider:
import { useSpotifyClient } from "spotify-react-query"
const client = useSpotifyClient()
client.getTracks(["3n3Ppam7vgaVa1iaRUc9Lp"]).then((res) => console.log(res.body))The returned client is whatever you passed to <SpotifyQueryProvider />, narrowed to the SpotifyClient interface. If you provided a spotify-web-api-node instance, all of its extra methods are still available at runtime — you can cast back to its type to access them.
Bring your own client
SpotifyClient is a structural interface. If you need a custom transport (e.g. a backend proxy that adds your own auth), implement only the methods you use:
import type { SpotifyClient } from "spotify-react-query"
const customClient: SpotifyClient = {
getAccessToken: () => myAuth.token,
getTracks: async (ids) => {
const res = await fetch(`/api/spotify/tracks?ids=${ids.join(",")}`)
return { statusCode: res.status, body: await res.json() }
},
// ...other methods
}