如何将异步获取的Audius服务地址传入Redux Toolkit Query的createApi配置
解决方案
首先需要修正你写的getHost函数的基础问题:函数没有返回值,所以调用后无法拿到host结果,修正后代码如下:
async function getHost() { const sample = (arr) => arr[Math.floor(Math.random() * arr.length)] const host = await fetch('https://api.audius.co') .then(r => r.json()) .then(j => j.data) .then(d => sample(d)) return host // 新增返回值 }
下面提供两种适配Redux Toolkit Query的实现方案,均不需要在组件内使用useState,不会产生额外性能损耗:
方案1:动态baseQuery(推荐,侵入性最小)
自定义baseQuery逻辑,首次请求时自动拉取最优host并全局缓存,后续所有请求复用缓存结果,现有hooks调用逻辑完全不需要修改:
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react' // 全局缓存host,避免重复请求拉取节点列表 let cachedHost = null const audiusVersion = `/v1` const appName = `app_name=ZION` const section = [`/users`, `/playlists`, `/tracks`] const search = `/search?query=` async function getHost() { if (cachedHost) return cachedHost const sample = (arr) => arr[Math.floor(Math.random() * arr.length)] const host = await fetch('https://api.audius.co') .then(r => r.json()) .then(j => j.data) .then(d => sample(d)) cachedHost = host return host } // 自定义动态baseQuery,首次执行自动获取host const dynamicBaseQuery = async (args, api, extraOptions) => { const host = await getHost() const baseUrl = host + audiusVersion const rawBaseQuery = fetchBaseQuery({ baseUrl }) return rawBaseQuery(args, api, extraOptions) } export const audiusApi = createApi({ reducerPath: 'audiusApi', baseQuery: dynamicBaseQuery, // 替换为自定义动态baseQuery endpoints: (builder) => ({ searchUsers: builder.query({ // 注意新增&拼接参数,避免query参数格式错误 query: (searchQuery) => `${section[0]}${search}${searchQuery}&${appName}` }), // 其余原有endpoints代码保持不变 }), }) // 原有导出的hooks完全不变,可正常使用 export const { useSearchUsersQuery, useGetUserQuery, useGetUsersFavTracksQuery, useGetUsersRepostsQuery, useGetUserMostUsedTagsQuery, useGetUserTracksQuery, useSearchPlaylistQuery, useGetPlaylistQuery, useGetPlaylistTracksQuery, useSearchTracksQuery, useTrendingTracksQuery, useGetTrackQuery, useStreamTrackQuery } = audiusApi
方案2:预初始化host再创建API
应用启动时先拉取最优host,再初始化RTK Query实例和Redux store,所有请求无需额外判断逻辑,性能最优:
第一步:封装API创建逻辑
// audiusApi.js import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react' const audiusVersion = `/v1` export const appName = `app_name=ZION` export const section = [`/users`, `/playlists`, `/tracks`] export const search = `/search?query=` // 接收host参数动态创建API实例 export const createAudiusApi = (host) => { const baseUrl = host + audiusVersion return createApi({ reducerPath: 'audiusApi', baseQuery: fetchBaseQuery({ baseUrl }), endpoints: (builder) => ({ searchUsers: builder.query({ query: (searchQuery) => `${section[0]}${search}${searchQuery}&${appName}` }), // 其余原有endpoints代码保持不变 }) }) }
第二步:改写store初始化逻辑
// store.js import { configureStore } from '@reduxjs/toolkit' import { createAudiusApi } from './audiusApi' export default async function initStore() { // 先拉取最优host const sample = (arr) => arr[Math.floor(Math.random() * arr.length)] const host = await fetch('https://api.audius.co') .then(r => r.json()) .then(j => j.data) .then(d => sample(d)) // 动态创建API实例 const audiusApi = createAudiusApi(host) // 初始化store const store = configureStore({ reducer: { [audiusApi.reducerPath]: audiusApi.reducer, // 其余你的业务reducer保持不变 }, middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(audiusApi.middleware), }) return { store, audiusApi } }
第三步:改写应用入口逻辑
// main.jsx (对应你的应用入口文件) import React from 'react' import ReactDOM from 'react-dom/client' import { Provider } from 'react-redux' import App from './App' import initStore from './store' initStore().then(({ store, audiusApi }) => { // 可将API导出的hooks挂载到全局变量供组件调用,也可按你的项目规范导出 window.audiusHooks = audiusApi ReactDOM.createRoot(document.getElementById('root')).render( <Provider store={store}> <App /> </Provider> ) })
注意事项:原有参数拼接逻辑存在问题,appName前需要添加&符号避免query参数拼接错误。
内容的提问来源于stack exchange,提问作者Giacomo Gagliano
相关产品推荐
相关产品推荐

