我正在尝试在货币转换器应用程序中使用RTK查询。此应用程序基于2 API。
首先,我要获取一个带有货币的对象。然后,我获取一系列国家并对其进行过滤,这取决于该国是否拥有这种货币。
存储代码:
export const store = configureStore({
reducer: {
[currenciesAPI.reducerPath]: currenciesAPI.reducer,
[countriesAPI.reducerPath]: countriesAPI.reducer,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(currenciesAPI.middleware, countriesAPI.middleware)
})
API代码:
export const currenciesAPI = createApi({
reducerPath: 'currenciesAPI',
baseQuery: fetchBaseQuery({ baseUrl: 'https://api.frankfurter.app'}),
endpoints: (build) => ({
fetchAllCurrencies: build.query<Currencies, void>({
query: () => ({
url: '/currencies'
}),
})
})
})
export const countriesAPI = createApi({
reducerPath: 'countriesAPI',
//tagTypes: ['Country'],
baseQuery: fetchBaseQuery({ baseUrl: 'https://restcountries.com/v3.1'}),
endpoints: (build) => ({
fetchAllCountries: build.query<TransformedCountries[], string>({
query: () => ({
url: '/all'
}),
transformResponse: (response: Countries[]) : TransformedCountries[] => {
const countriesWithCurrency = response.filter((country: Countries) => country.currencies) // <-- MUTATING DATA HERE AND BELOW IS NORMAL?
const transformedCountriesArray = countriesWithCurrency.map((item: Countries) => {
const keys = Object.keys(item.currencies)
const firstKey = keys[0]
return {
name: item.name.common,
currencyFullName: item.currencies[firstKey].name,
currencyShortName: firstKey,
currencySymbol: item.currencies[firstKey].symbol,
flag: item.flags.svg
}
})
const finalCountriesArray = transformedCountriesArray.sort((a: TransformedCountries, b: TransformedCountries) => (a.name > b.name) ? 1 : (a.name < b.name) ? -1 : 0)
return finalCountriesArray
}
})
})
})
组件代码:
const App: React.FC = () => {
const {
data: currenciesData,
error: currenciesError,
isLoading: currenciesIsLoading
} = useFetchAllCurrenciesQuery()
const {
data: countriesData,
error: countriesError,
isLoading: countriesIsLoading
} = useFetchAllCountriesQuery('', {
selectFromResult: ({ data, error, isLoading }) => ({
data: data?.filter((country: TransformedCountries) => currenciesData && currenciesData[country.currencyShortName]), // <-- MUTATING DATA HERE AND BELOW IS NORMAL?
error,
isLoading
}),
skip: !currenciesData
})
...
问题:
- 使用";跳过";或";skipToken";选项,如果您的第二个查询取决于第一个查询的结果?有更好的模式吗
- 在";transformResponse";就像我在国家API中所做的那样,然后在";selectFromResult;在应用程序组件中使用FetchAllCountrysQuery中的选项?有更好的模式吗
- 什么是一个好的模式来处理两个";isLoading;和两个";错误";在这种情况下的组件中
我可以看到更多的陷阱,但要回答以下问题:
-
是的,一般来说还可以,但在您的情况下看起来并没有真正的意义。如果
useFetchAllCountriesQuery
有查询参数,这是useFetchAllCurrenciesQuery
结果中所期望的-听起来不错。如果这些结果在selectFromResult
中使用-情况并非如此。 -
再说一遍,它总体上是可以的,但在你的情况下似乎用错了方法。所有这些转换都可以在两个钩子调用之后从
transformResponse
中执行。 -
这在一定程度上取决于您以后将如何使用它,但一般来说,只需添加带有sum:的新常量即可
const isLoading = currenciesIsLoading || countriesIsLoading;
并在UI中使用它。
总结一下,我会这样做:
const getCountriesWithCurrency = (currencies, countries) => {
if (currencies && countries ) {
return countries?.filter(country => currenciesData &&
currencies[country.currencyShortName])
}
}
const App: React.FC = () => {
const {
data: currenciesData,
error: currenciesError,
isError: currenciesIsError,
isLoading: currenciesIsLoading
} = useFetchAllCurrenciesQuery()
const {
data: countriesData,
error: countriesError,
isError: countriesIsError,
isLoading: countriesIsLoading
} = useFetchAllCountriesQuery()
const isLoading = currenciesIsLoading || countriesIsLoading;
const isError = currenciesIsError || countriesIsError;
const countries = getCountriesWithCurrency(currenciesData, countriesData);
...
错误对象也可以以某种方式聚合,这取决于您对它的需求以及顺序。很可能您不需要聚合它们,只需根据isError显示错误状态,并分别记录这两个错误对象。
最让我担心的是,让我更难定义正确的代码组合的是transformResponse
部分中的countriesAPI
定义,在这里你可以解析国内的所有货币。
我认为嵌套对象是一种糟糕的模式。只要有一个关系就足够了;属于";在一系列id或代码中指向国家。或者像使用firstKey一样只使用第一个货币id,但不要将其解析为完整对象。API定义应仅与一个特定实体耦合。在你的情况下,这是一个国家,所以它应该与货币无关。
顺便说一句,selectFromResult
在这里很有用,可以汇总各国使用的所有货币,比如
selectFromResult: ({ data, error, isLoading }) => ({
data,
error,
isLoading,
relatedCurrencies: data?.reduce((acc, country) => ([...acc, ...Object.keys(country.currencies)]), [])
}),
稍后,您可以通过调用货币API来获取货币详细信息,但不是所有这些信息,而是您真正需要的信息-针对相关货币中的一个或多个id,或针对一个国家。
总体建议是将这些货币和国家/地区的提取、过滤和isError|isLoading suming-out of react组件转移到一个单独的自定义挂钩中,该挂钩将只返回一个准备好的数据和标记,该组件将实际使用这些数据和标记。它会让它变得非常清楚(