我有一个带有react-query的next.js项目。基本上我需要做的是在主页上显示 API 中的所有国家/地区,但还有一个按名称搜索的输入,以及一个按区域搜索的选择。我如何更改基于此调用的查询?
我想过将数据保存到 useState 然后显示它,但这似乎浪费了反应查询的潜力。这是我组织代码的方式:
国家.service.ts
import { Regions } from '@/queries/types';
import axios from 'axios';
export class CountriesService {
static client = axios.create({
baseURL: `${process.env.NEXT_PUBLIC_API_URL}`,
});
static async getAllCountries() {
const response = await CountriesService.client.get('/all');
return response.data;
}
static async getCountryByName(name: string) {
const response = await CountriesService.client.get(`/name/${name}`);
return response.data;
}
static async getCountryByRegion(region: Regions) {
const response = await CountriesService.client.get(`/region/${region}`);
return response.data;
}
}
国家.query.ts
import { useQuery } from '@tanstack/react-query';
import { CountriesService } from '@/services/countries.service';
import { Regions } from './types';
export class CountriesQuery {
static getAllCountries() {
return useQuery({
queryKey: ['get-all-countries'],
queryFn: async () => {
const data = await CountriesService.getAllCountries();
return data;
},
});
}
static getCountryByName({ name }: { name: string }) {
return useQuery({
queryKey: ['get-country-by-name'],
queryFn: async () => {
const data = await CountriesService.getCountryByName(name);
return data;
},
});
}
static getCountryByRegion({ region }: { region: Regions }) {
return useQuery({
queryKey: ['get-country-by-region'],
queryFn: async () => {
const data = await CountriesService.getCountryByName(region);
return data;
},
});
}
}
页面.tsx
'use client';
import { CountryCard } from "@/components/country-card";
import { CountriesQuery } from "@/queries/countries.query";
import { Country } from "@/queries/types";
import { MagnifyingGlass } from "@phosphor-icons/react";
import { useState } from "react";
export default function Home() {
const [searchName, setSearchName] = useState('');
const { data, isLoading} = CountriesQuery.getAllCountries();
const handleSearchByName = async (e: React.ChangeEvent<HTMLInputElement>) => {
setSearchName(e.target.value);
};
if (isLoading) {
//make skeleton
return;
};
return (
<main>
<div>
<input onChange={handleSearchByName} placeholder="Search for a country..." />
<button><MagnifyingGlass weight="bold" /></button>
</div>
<div>
{data.map((country: Country) => (
<div key={country.name.common} >
<CountryCard
flagSrc={country.flags.png}
name={country.name.common}
population={country.population}
region={country.region}
capital={country.capital}
/>
</div>
))}
</div>
</main>
)
}
您过度指定了自定义查询挂钩(并且还违反了挂钩规则)。
将其实现为自定义挂钩的正确方法如下:
export const useCountryQuery({ name, region, ...options } = {}) {
return useQuery({
queryKey: ['get-country', {name, region}]}
queryFn: () => {
if(name) {
return CountriesService.getCountryByName(name);
}
if(region) {
return CountriesService.getCountryByRegion(region);
}
return CountriesService.getAllCountries();
},
...options
})
}
用法如下:
const [searchName, setSearchName] = useState('');
const { data, isLoading } = useCountryQuery({name: searchName});
const handleSearchByName = async (e: React.ChangeEvent<HTMLInputElement>) => {
setSearchName(e.target.value);
};
// ...