mirror of
https://github.com/GiriNeko/YesPlayMusic.git
synced 2025-12-17 13:48:02 +00:00
feat: updates
This commit is contained in:
parent
47e41dea9b
commit
ebebf2a733
160 changed files with 4148 additions and 2001 deletions
|
|
@ -7,37 +7,33 @@ import {
|
|||
AlbumApiNames,
|
||||
FetchAlbumResponse,
|
||||
} from '@/shared/api/Album'
|
||||
import { useQuery } from 'react-query'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
|
||||
const fetch = async (params: FetchAlbumParams, noCache?: boolean) => {
|
||||
const album = await fetchAlbum(params, !!noCache)
|
||||
const fetch = async (params: FetchAlbumParams) => {
|
||||
const album = await fetchAlbum(params)
|
||||
if (album?.album?.songs) {
|
||||
album.album.songs = album.songs
|
||||
}
|
||||
return album
|
||||
}
|
||||
|
||||
const fetchFromCache = (id: number): FetchAlbumResponse =>
|
||||
const fetchFromCache = (params: FetchAlbumParams): FetchAlbumResponse =>
|
||||
window.ipcRenderer?.sendSync(IpcChannels.GetApiCacheSync, {
|
||||
api: APIs.Album,
|
||||
query: { id },
|
||||
query: params,
|
||||
})
|
||||
|
||||
export default function useAlbum(params: FetchAlbumParams, noCache?: boolean) {
|
||||
return useQuery(
|
||||
[AlbumApiNames.FetchAlbum, params.id],
|
||||
() => fetch(params, noCache),
|
||||
{
|
||||
enabled: !!params.id,
|
||||
staleTime: 24 * 60 * 60 * 1000, // 24 hours
|
||||
placeholderData: () => fetchFromCache(params.id),
|
||||
}
|
||||
)
|
||||
export default function useAlbum(params: FetchAlbumParams) {
|
||||
return useQuery([AlbumApiNames.FetchAlbum, params], () => fetch(params), {
|
||||
enabled: !!params.id,
|
||||
staleTime: 24 * 60 * 60 * 1000, // 24 hours
|
||||
placeholderData: () => fetchFromCache(params),
|
||||
})
|
||||
}
|
||||
|
||||
export function fetchAlbumWithReactQuery(params: FetchAlbumParams) {
|
||||
return reactQueryClient.fetchQuery(
|
||||
[AlbumApiNames.FetchAlbum, params.id],
|
||||
[AlbumApiNames.FetchAlbum, params],
|
||||
() => fetch(params),
|
||||
{
|
||||
staleTime: Infinity,
|
||||
|
|
@ -46,9 +42,9 @@ export function fetchAlbumWithReactQuery(params: FetchAlbumParams) {
|
|||
}
|
||||
|
||||
export async function prefetchAlbum(params: FetchAlbumParams) {
|
||||
if (fetchFromCache(params.id)) return
|
||||
if (fetchFromCache(params)) return
|
||||
await reactQueryClient.prefetchQuery(
|
||||
[AlbumApiNames.FetchAlbum, params.id],
|
||||
[AlbumApiNames.FetchAlbum, params],
|
||||
() => fetch(params),
|
||||
{
|
||||
staleTime: Infinity,
|
||||
|
|
|
|||
|
|
@ -6,25 +6,46 @@ import {
|
|||
ArtistApiNames,
|
||||
FetchArtistResponse,
|
||||
} from '@/shared/api/Artist'
|
||||
import { useQuery } from 'react-query'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import reactQueryClient from '@/web/utils/reactQueryClient'
|
||||
|
||||
export default function useArtist(
|
||||
params: FetchArtistParams,
|
||||
noCache?: boolean
|
||||
) {
|
||||
const fetchFromCache = (id: number): FetchArtistResponse =>
|
||||
window.ipcRenderer?.sendSync(IpcChannels.GetApiCacheSync, {
|
||||
api: APIs.Artist,
|
||||
query: {
|
||||
id,
|
||||
},
|
||||
})
|
||||
|
||||
export default function useArtist(params: FetchArtistParams) {
|
||||
return useQuery(
|
||||
[ArtistApiNames.FetchArtist, params],
|
||||
() => fetchArtist(params, !!noCache),
|
||||
() => fetchArtist(params),
|
||||
{
|
||||
enabled: !!params.id && params.id > 0 && !isNaN(Number(params.id)),
|
||||
staleTime: 5 * 60 * 1000, // 5 mins
|
||||
placeholderData: (): FetchArtistResponse =>
|
||||
window.ipcRenderer?.sendSync(IpcChannels.GetApiCacheSync, {
|
||||
api: APIs.Artist,
|
||||
query: {
|
||||
id: params.id,
|
||||
},
|
||||
}),
|
||||
placeholderData: () => fetchFromCache(params.id),
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
export function fetchArtistWithReactQuery(params: FetchArtistParams) {
|
||||
return reactQueryClient.fetchQuery(
|
||||
[ArtistApiNames.FetchArtist, params],
|
||||
() => fetchArtist(params),
|
||||
{
|
||||
staleTime: Infinity,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
export async function prefetchArtist(params: FetchArtistParams) {
|
||||
if (fetchFromCache(params.id)) return
|
||||
await reactQueryClient.prefetchQuery(
|
||||
[ArtistApiNames.FetchArtist, params],
|
||||
() => fetchArtist(params),
|
||||
{
|
||||
staleTime: Infinity,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@ import {
|
|||
ArtistApiNames,
|
||||
FetchArtistAlbumsResponse,
|
||||
} from '@/shared/api/Artist'
|
||||
import { useQuery } from 'react-query'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
|
||||
export default function useUserAlbums(params: FetchArtistAlbumsParams) {
|
||||
export default function useArtistAlbums(params: FetchArtistAlbumsParams) {
|
||||
return useQuery(
|
||||
[ArtistApiNames.FetchArtistAlbums, params],
|
||||
async () => {
|
||||
|
|
|
|||
30
packages/web/api/hooks/useArtistMV.ts
Normal file
30
packages/web/api/hooks/useArtistMV.ts
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
import { fetchArtistMV } from '@/web/api/artist'
|
||||
import { IpcChannels } from '@/shared/IpcChannels'
|
||||
import { APIs } from '@/shared/CacheAPIs'
|
||||
import {
|
||||
FetchArtistMVParams,
|
||||
ArtistApiNames,
|
||||
FetchArtistMVResponse,
|
||||
} from '@/shared/api/Artist'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
|
||||
export default function useArtistMV(params: FetchArtistMVParams) {
|
||||
return useQuery(
|
||||
[ArtistApiNames.FetchArtistMV, params],
|
||||
async () => {
|
||||
const data = await fetchArtistMV(params)
|
||||
return data
|
||||
},
|
||||
{
|
||||
enabled: !!params.id && params.id !== 0,
|
||||
staleTime: 3600000,
|
||||
// placeholderData: (): FetchArtistMVResponse =>
|
||||
// window.ipcRenderer?.sendSync(IpcChannels.GetApiCacheSync, {
|
||||
// api: APIs.ArtistAlbum,
|
||||
// query: {
|
||||
// id: params.id,
|
||||
// },
|
||||
// }),
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
@ -6,7 +6,7 @@ import {
|
|||
ArtistApiNames,
|
||||
FetchArtistResponse,
|
||||
} from '@/shared/api/Artist'
|
||||
import { useQuery } from 'react-query'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
|
||||
export default function useArtists(ids: number[]) {
|
||||
return useQuery(
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import {
|
|||
} from '@/shared/api/Track'
|
||||
import { APIs } from '@/shared/CacheAPIs'
|
||||
import { IpcChannels } from '@/shared/IpcChannels'
|
||||
import { useQuery } from 'react-query'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
|
||||
export default function useLyric(params: FetchLyricParams) {
|
||||
return useQuery(
|
||||
|
|
|
|||
31
packages/web/api/hooks/useMV.ts
Normal file
31
packages/web/api/hooks/useMV.ts
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import { fetchMV, fetchMVUrl } from '@/web/api/mv'
|
||||
import { IpcChannels } from '@/shared/IpcChannels'
|
||||
import { APIs } from '@/shared/CacheAPIs'
|
||||
import {
|
||||
MVApiNames,
|
||||
FetchMVParams,
|
||||
FetchMVResponse,
|
||||
FetchMVUrlParams,
|
||||
} from '@/shared/api/MV'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
|
||||
export default function useMV(params: FetchMVParams) {
|
||||
return useQuery([MVApiNames.FetchMV, params], () => fetchMV(params), {
|
||||
enabled: !!params.mvid && params.mvid > 0 && !isNaN(Number(params.mvid)),
|
||||
staleTime: 5 * 60 * 1000, // 5 mins
|
||||
// placeholderData: (): FetchMVResponse =>
|
||||
// window.ipcRenderer?.sendSync(IpcChannels.GetApiCacheSync, {
|
||||
// api: APIs.SimilarArtist,
|
||||
// query: {
|
||||
// id: params.id,
|
||||
// },
|
||||
// }),
|
||||
})
|
||||
}
|
||||
|
||||
export function useMVUrl(params: FetchMVUrlParams) {
|
||||
return useQuery([MVApiNames.FetchMVUrl, params], () => fetchMVUrl(params), {
|
||||
enabled: !!params.id && params.id > 0 && !isNaN(Number(params.id)),
|
||||
staleTime: 60 * 60 * 1000, // 60 mins
|
||||
})
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@ import reactQueryClient from '@/web/utils/reactQueryClient'
|
|||
|
||||
export function fetchPersonalFMWithReactQuery() {
|
||||
return reactQueryClient.fetchQuery(
|
||||
PersonalFMApiNames.FetchPersonalFm,
|
||||
[PersonalFMApiNames.FetchPersonalFm],
|
||||
async () => {
|
||||
const data = await fetchPersonalFM()
|
||||
if (!data.data?.length) {
|
||||
|
|
|
|||
|
|
@ -7,10 +7,10 @@ import {
|
|||
PlaylistApiNames,
|
||||
FetchPlaylistResponse,
|
||||
} from '@/shared/api/Playlists'
|
||||
import { useQuery } from 'react-query'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
|
||||
const fetch = (params: FetchPlaylistParams, noCache?: boolean) => {
|
||||
return fetchPlaylist(params, !!noCache)
|
||||
const fetch = (params: FetchPlaylistParams) => {
|
||||
return fetchPlaylist(params)
|
||||
}
|
||||
|
||||
export const fetchFromCache = (id: number): FetchPlaylistResponse | undefined =>
|
||||
|
|
@ -19,13 +19,10 @@ export const fetchFromCache = (id: number): FetchPlaylistResponse | undefined =>
|
|||
query: { id },
|
||||
})
|
||||
|
||||
export default function usePlaylist(
|
||||
params: FetchPlaylistParams,
|
||||
noCache?: boolean
|
||||
) {
|
||||
export default function usePlaylist(params: FetchPlaylistParams) {
|
||||
return useQuery(
|
||||
[PlaylistApiNames.FetchPlaylist, params],
|
||||
() => fetch(params, noCache),
|
||||
() => fetch(params),
|
||||
{
|
||||
enabled: !!(params.id && params.id > 0 && !isNaN(Number(params.id))),
|
||||
refetchOnWindowFocus: true,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import {
|
|||
ArtistApiNames,
|
||||
FetchSimilarArtistsResponse,
|
||||
} from '@/shared/api/Artist'
|
||||
import { useQuery } from 'react-query'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
|
||||
export default function useSimilarArtists(params: FetchSimilarArtistsParams) {
|
||||
return useQuery(
|
||||
|
|
@ -15,6 +15,7 @@ export default function useSimilarArtists(params: FetchSimilarArtistsParams) {
|
|||
{
|
||||
enabled: !!params.id && params.id > 0 && !isNaN(Number(params.id)),
|
||||
staleTime: 5 * 60 * 1000, // 5 mins
|
||||
retry: 0,
|
||||
placeholderData: (): FetchSimilarArtistsResponse =>
|
||||
window.ipcRenderer?.sendSync(IpcChannels.GetApiCacheSync, {
|
||||
api: APIs.SimilarArtist,
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import {
|
|||
TrackApiNames,
|
||||
} from '@/shared/api/Track'
|
||||
import { APIs } from '@/shared/CacheAPIs'
|
||||
import { useQuery } from 'react-query'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
|
||||
export default function useTracks(params: FetchTracksParams) {
|
||||
return useQuery(
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { FetchTracksParams, TrackApiNames } from '@/shared/api/Track'
|
||||
import { useInfiniteQuery } from 'react-query'
|
||||
import { useInfiniteQuery } from '@tanstack/react-query'
|
||||
import { fetchTracks } from '../track'
|
||||
|
||||
// 100 tracks each page
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@ import { fetchUserAccount } from '@/web/api/user'
|
|||
import { UserApiNames, FetchUserAccountResponse } from '@/shared/api/User'
|
||||
import { APIs } from '@/shared/CacheAPIs'
|
||||
import { IpcChannels } from '@/shared/IpcChannels'
|
||||
import { useQuery } from 'react-query'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
|
||||
export default function useUser() {
|
||||
return useQuery(UserApiNames.FetchUserAccount, fetchUserAccount, {
|
||||
return useQuery([UserApiNames.FetchUserAccount], fetchUserAccount, {
|
||||
refetchOnWindowFocus: true,
|
||||
placeholderData: (): FetchUserAccountResponse | undefined =>
|
||||
window.ipcRenderer?.sendSync(IpcChannels.GetApiCacheSync, {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { likeAAlbum } from '@/web/api/album'
|
||||
import { useMutation, useQuery, useQueryClient } from 'react-query'
|
||||
import { useMutation, useQuery } from '@tanstack/react-query'
|
||||
import useUser from './useUser'
|
||||
import { IpcChannels } from '@/shared/IpcChannels'
|
||||
import { APIs } from '@/shared/CacheAPIs'
|
||||
|
|
@ -10,11 +10,15 @@ import {
|
|||
} from '@/shared/api/User'
|
||||
import { fetchUserAlbums } from '../user'
|
||||
import toast from 'react-hot-toast'
|
||||
import reactQueryClient from '@/web/utils/reactQueryClient'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import { AlbumApiNames, FetchAlbumResponse } from '@/shared/api/Album'
|
||||
|
||||
export default function useUserAlbums(params: FetchUserAlbumsParams = {}) {
|
||||
const { data: user } = useUser()
|
||||
const uid = user?.profile?.userId ?? 0
|
||||
return useQuery(
|
||||
[UserApiNames.FetchUserAlbums, user?.profile?.userId ?? 0],
|
||||
[UserApiNames.FetchUserAlbums, uid],
|
||||
() => fetchUserAlbums(params),
|
||||
{
|
||||
refetchOnWindowFocus: true,
|
||||
|
|
@ -28,53 +32,91 @@ export default function useUserAlbums(params: FetchUserAlbumsParams = {}) {
|
|||
}
|
||||
|
||||
export const useMutationLikeAAlbum = () => {
|
||||
const queryClient = useQueryClient()
|
||||
const { data: user } = useUser()
|
||||
const { data: userAlbums } = useUserAlbums({ limit: 2000 })
|
||||
const uid = user?.account?.id ?? 0
|
||||
const uid = user?.profile?.userId ?? 0
|
||||
const key = [UserApiNames.FetchUserAlbums, uid]
|
||||
|
||||
return useMutation(
|
||||
async (album: Album) => {
|
||||
if (!album.id || userAlbums?.data === undefined) {
|
||||
async (albumID: number) => {
|
||||
if (!albumID || userAlbums?.data === undefined) {
|
||||
throw new Error('album id is required or userAlbums is undefined')
|
||||
}
|
||||
const response = await likeAAlbum({
|
||||
id: album.id,
|
||||
t: userAlbums?.data.findIndex(a => a.id === album.id) > -1 ? 2 : 1,
|
||||
id: albumID,
|
||||
t: userAlbums?.data.findIndex(a => a.id === albumID) > -1 ? 2 : 1,
|
||||
})
|
||||
if (response.code !== 200) throw new Error((response as any).msg)
|
||||
return response
|
||||
},
|
||||
{
|
||||
onMutate: async album => {
|
||||
onMutate: async albumID => {
|
||||
// Cancel any outgoing refetches (so they don't overwrite our optimistic update)
|
||||
await queryClient.cancelQueries(key)
|
||||
await reactQueryClient.cancelQueries(key)
|
||||
|
||||
console.log(reactQueryClient.getQueryData(key))
|
||||
|
||||
// 如果还未获取用户收藏的专辑列表,则获取一次
|
||||
if (!reactQueryClient.getQueryData(key)) {
|
||||
await reactQueryClient.fetchQuery(key)
|
||||
}
|
||||
|
||||
// Snapshot the previous value
|
||||
const previousData = queryClient.getQueryData(key)
|
||||
const previousData = reactQueryClient.getQueryData(
|
||||
key
|
||||
) as FetchUserAlbumsResponse
|
||||
|
||||
// Optimistically update to the new value
|
||||
queryClient.setQueryData(key, old => {
|
||||
const userAlbums = old as FetchUserAlbumsResponse
|
||||
const albums = userAlbums.data
|
||||
const newAlbums =
|
||||
albums.findIndex(a => a.id === album.id) > -1
|
||||
? albums.filter(a => a.id !== album.id)
|
||||
: [...albums, album]
|
||||
return {
|
||||
...userAlbums,
|
||||
data: newAlbums,
|
||||
const isLiked = !!previousData?.data.find(a => a.id === albumID)
|
||||
const newAlbums = cloneDeep(previousData!)
|
||||
|
||||
console.log({ isLiked })
|
||||
|
||||
if (isLiked) {
|
||||
newAlbums.data = previousData.data.filter(a => a.id !== albumID)
|
||||
} else {
|
||||
// 从react-query缓存获取专辑
|
||||
|
||||
console.log({ albumID })
|
||||
|
||||
const albumFromCache: FetchAlbumResponse | undefined =
|
||||
reactQueryClient.getQueryData([
|
||||
AlbumApiNames.FetchAlbum,
|
||||
{ id: albumID },
|
||||
])
|
||||
|
||||
console.log({ albumFromCache })
|
||||
|
||||
// 从api获取专辑
|
||||
const album: FetchAlbumResponse | undefined = albumFromCache
|
||||
? albumFromCache
|
||||
: await reactQueryClient.fetchQuery([
|
||||
AlbumApiNames.FetchAlbum,
|
||||
{ id: albumID },
|
||||
])
|
||||
|
||||
if (!album?.album) {
|
||||
toast.error('Failed to like album: unable to fetch album info')
|
||||
throw new Error('unable to fetch album info')
|
||||
}
|
||||
})
|
||||
newAlbums.data.unshift(album.album)
|
||||
|
||||
// Optimistically update to the new value
|
||||
reactQueryClient.setQueriesData(key, newAlbums)
|
||||
}
|
||||
|
||||
reactQueryClient.setQueriesData(key, newAlbums)
|
||||
|
||||
console.log({ newAlbums })
|
||||
|
||||
// Return a context object with the snapshotted value
|
||||
return { previousData }
|
||||
},
|
||||
// If the mutation fails, use the context returned from onMutate to roll back
|
||||
onError: (err, trackID, context) => {
|
||||
queryClient.setQueryData(key, (context as any).previousData)
|
||||
toast((err as any).toString())
|
||||
onSettled: (data, error, albumID, context) => {
|
||||
if (data?.code !== 200) {
|
||||
reactQueryClient.setQueryData(key, (context as any).previousData)
|
||||
toast((error as any).toString())
|
||||
}
|
||||
},
|
||||
}
|
||||
)
|
||||
|
|
|
|||
|
|
@ -2,10 +2,19 @@ import { fetchUserArtists } from '@/web/api/user'
|
|||
import { UserApiNames, FetchUserArtistsResponse } from '@/shared/api/User'
|
||||
import { APIs } from '@/shared/CacheAPIs'
|
||||
import { IpcChannels } from '@/shared/IpcChannels'
|
||||
import { useQuery } from 'react-query'
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
|
||||
import toast from 'react-hot-toast'
|
||||
import { likeAArtist } from '../artist'
|
||||
import { ArtistApiNames, FetchArtistResponse } from '@/shared/api/Artist'
|
||||
import reactQueryClient from '@/web/utils/reactQueryClient'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
|
||||
const KEYS = {
|
||||
useUserArtists: [UserApiNames.FetchUserArtists],
|
||||
}
|
||||
|
||||
export default function useUserArtists() {
|
||||
return useQuery([UserApiNames.FetchUserArtist], fetchUserArtists, {
|
||||
return useQuery(KEYS.useUserArtists, fetchUserArtists, {
|
||||
refetchOnWindowFocus: true,
|
||||
placeholderData: (): FetchUserArtistsResponse =>
|
||||
window.ipcRenderer?.sendSync(IpcChannels.GetApiCacheSync, {
|
||||
|
|
@ -13,3 +22,85 @@ export default function useUserArtists() {
|
|||
}),
|
||||
})
|
||||
}
|
||||
|
||||
export const useMutationLikeAArtist = () => {
|
||||
const { data: userLikedArtists } = useUserArtists()
|
||||
|
||||
return useMutation(
|
||||
async (artistID: number) => {
|
||||
if (!artistID || !userLikedArtists?.data) {
|
||||
throw new Error('artistID is required or userLikedArtists is undefined')
|
||||
}
|
||||
const response = await likeAArtist({
|
||||
id: artistID,
|
||||
like: !userLikedArtists.data.find(a => a.id === artistID),
|
||||
})
|
||||
if (response.code !== 200) throw new Error((response as any).msg)
|
||||
return response
|
||||
},
|
||||
{
|
||||
onMutate: async artistID => {
|
||||
// Cancel any outgoing refetches (so they don't overwrite our optimistic update)
|
||||
await reactQueryClient.cancelQueries(KEYS.useUserArtists)
|
||||
|
||||
// 如果还未获取用户收藏的歌手列表,则获取一次
|
||||
if (!reactQueryClient.getQueryData(KEYS.useUserArtists)) {
|
||||
await reactQueryClient.fetchQuery(KEYS.useUserArtists)
|
||||
}
|
||||
|
||||
// Snapshot the previous value
|
||||
const previousData = reactQueryClient.getQueryData(
|
||||
KEYS.useUserArtists
|
||||
) as FetchUserArtistsResponse
|
||||
|
||||
const isLiked = !!previousData?.data.find(a => a.id === artistID)
|
||||
const newLikedArtists = cloneDeep(previousData!)
|
||||
|
||||
if (isLiked) {
|
||||
newLikedArtists.data = previousData.data.filter(
|
||||
a => a.id !== artistID
|
||||
)
|
||||
} else {
|
||||
// 从react-query缓存获取歌手信息
|
||||
const artistFromCache: FetchArtistResponse | undefined =
|
||||
reactQueryClient.getQueryData([
|
||||
ArtistApiNames.FetchArtist,
|
||||
{ id: artistID },
|
||||
])
|
||||
|
||||
// 从api获取歌手信息
|
||||
const artist: FetchArtistResponse | undefined = artistFromCache
|
||||
? artistFromCache
|
||||
: await reactQueryClient.fetchQuery([
|
||||
ArtistApiNames.FetchArtist,
|
||||
{ id: artistID },
|
||||
])
|
||||
|
||||
if (!artist?.artist) {
|
||||
toast.error('Failed to like artist: unable to fetch artist info')
|
||||
throw new Error('unable to fetch artist info')
|
||||
}
|
||||
newLikedArtists.data.unshift(artist.artist)
|
||||
|
||||
// Optimistically update to the new value
|
||||
reactQueryClient.setQueriesData(KEYS.useUserArtists, newLikedArtists)
|
||||
}
|
||||
|
||||
reactQueryClient.setQueriesData(KEYS.useUserArtists, newLikedArtists)
|
||||
|
||||
// Return a context object with the snapshotted value
|
||||
return { previousData }
|
||||
},
|
||||
// If the mutation fails, use the context returned from onMutate to roll back
|
||||
onSettled: (data, error, artistID, context) => {
|
||||
if (data?.code !== 200) {
|
||||
reactQueryClient.setQueryData(
|
||||
KEYS.useUserArtists,
|
||||
(context as any).previousData
|
||||
)
|
||||
toast((error as any).toString())
|
||||
}
|
||||
},
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { likeATrack } from '@/web/api/track'
|
||||
import useUser from './useUser'
|
||||
import { useMutation, useQueryClient } from 'react-query'
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query'
|
||||
import { IpcChannels } from '@/shared/IpcChannels'
|
||||
import { APIs } from '@/shared/CacheAPIs'
|
||||
import { fetchUserLikedTracksIDs } from '../user'
|
||||
|
|
@ -8,8 +8,9 @@ import {
|
|||
FetchUserLikedTracksIDsResponse,
|
||||
UserApiNames,
|
||||
} from '@/shared/api/User'
|
||||
import { useQuery } from 'react-query'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import toast from 'react-hot-toast'
|
||||
import reactQueryClient from '@/web/utils/reactQueryClient'
|
||||
|
||||
export default function useUserLikedTracksIDs() {
|
||||
const { data: user } = useUser()
|
||||
|
|
@ -33,7 +34,6 @@ export default function useUserLikedTracksIDs() {
|
|||
}
|
||||
|
||||
export const useMutationLikeATrack = () => {
|
||||
const queryClient = useQueryClient()
|
||||
const { data: user } = useUser()
|
||||
const { data: userLikedSongs } = useUserLikedTracksIDs()
|
||||
const uid = user?.account?.id ?? 0
|
||||
|
|
@ -54,13 +54,13 @@ export const useMutationLikeATrack = () => {
|
|||
{
|
||||
onMutate: async trackID => {
|
||||
// Cancel any outgoing refetches (so they don't overwrite our optimistic update)
|
||||
await queryClient.cancelQueries(key)
|
||||
await reactQueryClient.cancelQueries(key)
|
||||
|
||||
// Snapshot the previous value
|
||||
const previousData = queryClient.getQueryData(key)
|
||||
const previousData = reactQueryClient.getQueryData(key)
|
||||
|
||||
// Optimistically update to the new value
|
||||
queryClient.setQueryData(key, old => {
|
||||
reactQueryClient.setQueryData(key, old => {
|
||||
const likedSongs = old as FetchUserLikedTracksIDsResponse
|
||||
const ids = likedSongs.ids
|
||||
const newIds = ids.includes(trackID)
|
||||
|
|
@ -77,7 +77,7 @@ export const useMutationLikeATrack = () => {
|
|||
},
|
||||
// If the mutation fails, use the context returned from onMutate to roll back
|
||||
onError: (err, trackID, context) => {
|
||||
queryClient.setQueryData(key, (context as any).previousData)
|
||||
reactQueryClient.setQueryData(key, (context as any).previousData)
|
||||
toast((err as any).toString())
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { fetchListenedRecords } from '@/web/api/user'
|
|||
import { UserApiNames, FetchListenedRecordsResponse } from '@/shared/api/User'
|
||||
import { APIs } from '@/shared/CacheAPIs'
|
||||
import { IpcChannels } from '@/shared/IpcChannels'
|
||||
import { useQuery } from 'react-query'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import useUser from './useUser'
|
||||
|
||||
export default function useUserListenedRecords(params: {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,14 @@
|
|||
import { likeAPlaylist } from '@/web/api/playlist'
|
||||
import { useMutation, useQuery, useQueryClient } from 'react-query'
|
||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'
|
||||
import useUser from './useUser'
|
||||
import { IpcChannels } from '@/shared/IpcChannels'
|
||||
import { APIs } from '@/shared/CacheAPIs'
|
||||
import { fetchUserPlaylists } from '@/web/api/user'
|
||||
import { FetchUserPlaylistsResponse, UserApiNames } from '@/shared/api/User'
|
||||
import toast from 'react-hot-toast'
|
||||
import reactQueryClient from '@/web/utils/reactQueryClient'
|
||||
import { cloneDeep } from 'lodash-es'
|
||||
import { FetchPlaylistResponse, PlaylistApiNames } from '@/shared/api/Playlists'
|
||||
|
||||
export default function useUserPlaylists() {
|
||||
const { data: user } = useUser()
|
||||
|
|
@ -45,21 +48,20 @@ export default function useUserPlaylists() {
|
|||
}
|
||||
|
||||
export const useMutationLikeAPlaylist = () => {
|
||||
const queryClient = useQueryClient()
|
||||
const { data: user } = useUser()
|
||||
const { data: userPlaylists } = useUserPlaylists()
|
||||
const uid = user?.account?.id ?? 0
|
||||
const key = [UserApiNames.FetchUserPlaylists, uid]
|
||||
|
||||
return useMutation(
|
||||
async (playlist: Playlist) => {
|
||||
if (!playlist.id || userPlaylists?.playlist === undefined) {
|
||||
async (playlistID: number) => {
|
||||
if (!playlistID || userPlaylists?.playlist === undefined) {
|
||||
throw new Error('playlist id is required or userPlaylists is undefined')
|
||||
}
|
||||
const response = await likeAPlaylist({
|
||||
id: playlist.id,
|
||||
id: playlistID,
|
||||
t:
|
||||
userPlaylists.playlist.findIndex(p => p.id === playlist.id) > -1
|
||||
userPlaylists.playlist.findIndex(p => p.id === playlistID) > -1
|
||||
? 2
|
||||
: 1,
|
||||
})
|
||||
|
|
@ -67,34 +69,73 @@ export const useMutationLikeAPlaylist = () => {
|
|||
return response
|
||||
},
|
||||
{
|
||||
onMutate: async playlist => {
|
||||
onMutate: async playlistID => {
|
||||
// Cancel any outgoing refetches (so they don't overwrite our optimistic update)
|
||||
await queryClient.cancelQueries(key)
|
||||
await reactQueryClient.cancelQueries(key)
|
||||
|
||||
console.log(reactQueryClient.getQueryData(key))
|
||||
|
||||
// 如果还未获取用户收藏的专辑列表,则获取一次
|
||||
if (!reactQueryClient.getQueryData(key)) {
|
||||
await reactQueryClient.fetchQuery(key)
|
||||
}
|
||||
|
||||
// Snapshot the previous value
|
||||
const previousData = queryClient.getQueryData(key)
|
||||
const previousData = reactQueryClient.getQueryData(
|
||||
key
|
||||
) as FetchUserPlaylistsResponse
|
||||
|
||||
// Optimistically update to the new value
|
||||
queryClient.setQueryData(key, old => {
|
||||
const userPlaylists = old as FetchUserPlaylistsResponse
|
||||
const playlists = userPlaylists.playlist
|
||||
const newPlaylists =
|
||||
playlists.findIndex(p => p.id === playlist.id) > -1
|
||||
? playlists.filter(p => p.id !== playlist.id)
|
||||
: [...playlists, playlist]
|
||||
return {
|
||||
...userPlaylists,
|
||||
playlist: newPlaylists,
|
||||
const isLiked = !!previousData?.playlist.find(p => p.id === playlistID)
|
||||
const newPlaylists = cloneDeep(previousData!)
|
||||
|
||||
console.log({ isLiked })
|
||||
|
||||
if (isLiked) {
|
||||
newPlaylists.playlist = previousData.playlist.filter(
|
||||
p => p.id !== playlistID
|
||||
)
|
||||
} else {
|
||||
// 从react-query缓存获取歌单信息
|
||||
|
||||
const playlistFromCache: FetchPlaylistResponse | undefined =
|
||||
reactQueryClient.getQueryData([
|
||||
PlaylistApiNames.FetchPlaylist,
|
||||
{ id: playlistID },
|
||||
])
|
||||
|
||||
// 从api获取歌单信息
|
||||
const playlist: FetchPlaylistResponse | undefined = playlistFromCache
|
||||
? playlistFromCache
|
||||
: await reactQueryClient.fetchQuery([
|
||||
PlaylistApiNames.FetchPlaylist,
|
||||
{ id: playlistID },
|
||||
])
|
||||
|
||||
if (!playlist?.playlist) {
|
||||
toast.error(
|
||||
'Failed to like playlist: unable to fetch playlist info'
|
||||
)
|
||||
throw new Error('unable to fetch playlist info')
|
||||
}
|
||||
})
|
||||
newPlaylists.playlist.splice(1, 0, playlist.playlist)
|
||||
|
||||
// Optimistically update to the new value
|
||||
reactQueryClient.setQueriesData(key, newPlaylists)
|
||||
}
|
||||
|
||||
reactQueryClient.setQueriesData(key, newPlaylists)
|
||||
|
||||
console.log({ newPlaylists })
|
||||
|
||||
// Return a context object with the snapshotted value
|
||||
return { previousData }
|
||||
},
|
||||
// If the mutation fails, use the context returned from onMutate to roll back
|
||||
onError: (err, trackID, context) => {
|
||||
queryClient.setQueryData(key, (context as any).previousData)
|
||||
toast((err as any).toString())
|
||||
onSettled: (data, error, playlistID, context) => {
|
||||
if (data?.code !== 200) {
|
||||
reactQueryClient.setQueryData(key, (context as any).previousData)
|
||||
toast((error as any).toString())
|
||||
}
|
||||
},
|
||||
}
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue