Jak zbudować aplikację React za pomocą RTK-QUERY
Niemożliwe jest być Front-end developerem pracującym z Reactem i nie słyszeć o redux w swoim życiu. Większość firm używa redux w swojej bazie kodu, a znajomość podstawowych koncepcji stała się jedną z istot bycia Frontenderem. Istnieje wiele dyskusji na temat używania lub nie używania go w swoim produkcie. Prawda jest taka, że nigdy nie można znaleźć idealnego narzędzia do wszystkich projektów. Powinieneś zdecydować, które narzędzia najlepiej pasują do Twoich celów i produktu. Chociaż istnieją pewne zalety i wady każdego narzędzia, najważniejszą rzeczą jest kompromis między zaletami i wadami narzędzia dla CIEBIE .
RTK Query to potężne narzędzie do pobierania i buforowania danych. Został zaprojektowany w celu uproszczenia typowych przypadków ładowania danych w aplikacji internetowej, eliminując potrzebę samodzielnego pisania logiki pobierania i buforowania danych.
Jeśli używasz redux, zwłaszcza redux-toolkit , już wiesz, że rtk-query jest z nim wbudowaną zależnością. Istnieje wiele podobnych narzędzi, takich jak react-query, ale kiedy używasz redux-toolkit i masz już rtk-query w swoim pakiecie, dlaczego go nie użyć? Niektóre zalety trk-query to:
- Jest w pełni kompatybilny z redux
- Napisany w TypeScript
- Ulepsza warstwę usług, aby była bardziej użyteczna i przenosi Twój projekt z automatycznie generowanymi haczykami na wyższy poziom
- Można go śledzić i obserwować za pomocą redux-devtools
- Ma naprawdę ładne zachowanie buforowania
Warunek wstępny
- Powinieneś znać Reacta
- Powinieneś znać koncepcje redux i redux-toolkit i chcieć ich używać w swoim projekcie
- Doświadczenie z TypeScriptem jest plusem, ale możesz po prostu usunąć części TS z kodów i działa z JavaScriptem dla Ciebie :)
Jak to działa?
Jak wspomniałem wcześniej, rtk-query to narzędzie do pobierania, które zapewnia mnóstwo funkcji, dzięki którym Twój projekt jest bardziej przejrzysty i nadaje się do ponownego użycia. Twoje usługi mogą być tworzone w kształcie punktów końcowych i zapytań za pomocą createApi , które jest całkowicie podobne do createReducer . Generuje haczyki dla twoich zapytań i możesz ich łatwo używać w swoich komponentach. Nie będziesz już potrzebować stanów ładowania, obsługi błędów, funkcji ponownego pobierania, pobierania wstępnego za pomocą useEffect i parserów danych, ponieważ rtk-query zajmie się tym za Ciebie.
W rzeczywistości zapytania to najmniejsze elementy twoich usług, które mogą być GET lub POST w celu pobrania lub wysłania danych na serwer. Wszystkie zapytania związane z jednostką są spakowane w jednym punkcie końcowym, który jest tworzony przez createApi . W końcu warstwa usług jest kombinacją różnych punktów końcowych, w tym ich własnych zapytań.
rtk-query używa interfejsu API pobierania z JavaScript. Ale możesz skonfigurować go tak, aby używał axios lub graphql. Ponadto zawija twoje zapytania przez zanurzenie , więc mutacja danych nie jest już problemem.
Budowanie fundamentów
Możesz wybrać DOWOLNE narzędzia i konfigurację, które lubisz dla tego projektu. Użyję Vite, ale nie ma znaczenia, czy bardziej lubisz CRA, czy wolisz skonfigurować własną płytę kotłową. Po utworzeniu naszego projektu React powinniśmy zainstalować redux-toolkit + axios i skonfigurować go:
npm install @reduxjs/toolkit react-redux axios
// src/services/api.ts
const axiosBaseQuery =
(): BaseQueryFn<AxiosRequestConfig, unknown, AxiosError> =>
async ({ url, method, data, params }) => {
try {
Axios.defaults.baseURL = "https://jsonplaceholder.typicode.com/";
const result = await Axios({
url,
method,
data,
params,
});
return { data: result.data };
} catch (axiosError) {
const error = axiosError as AxiosError;
return {
error,
};
}
};
W tym projekcie wykorzystamy darmowe API JSONPlaceholder .
Po drugie, powinniśmy powiedzieć rtk-query, aby używał naszej niestandardowej funkcji zapytania zamiast JS fetch API. Jest to po prostu wykonalne, przekazując naszą funkcję do createApi .
// src/services/api.ts
export const apiService = createApi({
baseQuery: axiosBaseQuery(),
endpoints: () => ({}),
});
Na koniec musimy dodać apiService do sklepu redux i dodać sklep do naszej aplikacji:
// src/store/store.ts
export const store = configureStore({
reducer: {
[apiService.reducerPath]: apiService.reducer,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(apiService.middleware),
});
// src/main.tsx
<Provider store={store}>
<App />
</Provider>
Tworzymy naszą pierwszą usługę
Zaczynamy od punktu końcowego GET , aby pobrać listę postów z serwera. Możemy po prostu użyć injectEndpoint API z rtk-query, aby utworzyć nasze punkty końcowe i dodać je do naszej podstawowej warstwy usług.
// src/services/posts.ts
// Interface of JSONPlaceholder posts
export interface Post {
id: number;
userId: number;
title: string;
body: string;
}
export const postService = apiService.injectEndpoints({
endpoints: (build) => ({
// query<ResultType, QueryArg>
getPosts: build.query<Post[], null>({
query: () => ({ method: "GET", url: "posts" }),
}),
}),
});
// Auto-generated hooks
export const { useGetPostsQuery } = postService;
Następnie rtk-query tworzy haczyki, abyś mógł łatwo pobrać te zapytania. Możesz przekazać więcej ustawień do swoich konstruktorów zapytań, takich jak transformResponse , których nie omawiamy, ponieważ wykraczają poza zakres tego artykułu.
Skorzystajmy z naszej pierwszej usługi
Teraz pora skorzystać z naszej usługi. rtk-query wygenerował dla nas hak useGetPostsQuery . Ten hak zwraca obiekt składający się z kilku użytecznych wartości do użycia. Podobnie jak stan ładowania, błąd, zwrócone dane i funkcja ponownego pobierania.
- Stan ładowania: będzie prawdziwy , gdy wykonamy to zapytanie w naszym komponencie.
- Obiekt błędu: Jeśli nasze zapytanie nie powiedzie się, zostanie zwrócony obiekt błędu, w przeciwnym razie jest to null .
- dane: Nasze zwrócone dane. Jest pusty , dopóki nasze zapytanie nie zostanie pomyślnie wykonane .
- funkcja ponownego pobierania: możemy użyć tej funkcji, aby ponownie uruchomić zapytanie, kiedy tylko zajdzie taka potrzeba. Na przykład na wypadek, gdybyśmy chcieli mieć przycisk „Spróbuj ponownie” lub przycisk odświeżania.
// src/components/PostList.tsx
const PostList: React.FC<unknown> = () => {
const { data: posts, isLoading, error, refetch } = useGetPostsQuery(null);
if (isLoading) {
return <div>Loading posts...</div>;
}
if (error) {
return <ErrorBanner error={error as AxiosError} refetch={refetch} />;
}
return (
<div>
<h2>Posts</h2>
<div>
{posts?.map((post) => (
<div className="postItem">
<h4>{post.title}</h4>
<p>{post.body}</p>
</div>
))}
</div>
</div>
);
};
export default PostList;
Aby przejść dalej, omówimy również jedno zapytanie o mutację. Chcemy utworzyć post za pomocą formularza, który pobiera tytuł i treść od użytkowników. Zacznijmy od samego zapytania:
// src/services/posts.ts
export interface CreatePostDto {
title: string;
body: string;
}
export const postService = apiService.injectEndpoints({
endpoints: (build) => ({
// query<ResultType, QueryArg>
getPosts: build.query<Post[], null>({
query: () => ({ method: "GET", url: "posts" }),
}),
// We use mutation for POST endpoints
createPost: build.mutation<Post, CreatePostDto>({
query: (data) => ({
method: "POST",
url: "posts",
// We pass static userId to simplify this part
data: { userId: 1, ...data },
}),
}),
}),
});
// Auto-generated hooks
export const { useGetPostsQuery, useCreatePostMutation } = postService;
- Ponieważ chcemy dodać trochę danych metodą POST , używamy build.mutation zamiast build.query .
- Określiliśmy nowy interfejs dla argumentów naszego punktu końcowego i przekazaliśmy odpowiednie dane do naszego żądania axios.
// src/components/PostForm.tsx
const PostForm: React.FC<unknown> = () => {
const [title, setTitle] = useState<string>("");
const [body, setBody] = useState<string>("");
const [createPost, { isLoading }] = useCreatePostMutation();
const submitForm = async (e: FormEvent) => {
e.preventDefault();
try {
await createPost({ title, body });
} catch (e) {
console.log(e);
}
};
return (
<form onSubmit={submitForm}>
<input
name="title"
type="text"
placeholder="Title"
value={title}
onChange={(e) => setTitle(e.currentTarget.value)}
/>
<textarea
name="body"
placeholder="Body..."
rows={5}
value={body}
onChange={(e) => setBody(e.currentTarget.value)}
/>
<input
type="submit"
value={isLoading ? "Wait..." : "Submit"}
disabled={isLoading}
/>
</form>
);
};
export default PostForm;
Zawiń to
Omówiliśmy najważniejsze podstawowe koncepcje zapytania rtk. Zobaczyliśmy, jak możemy tworzyć nasze usługi i punkty końcowe w sposób modułowy oraz jak wykorzystywać fantastyczne automatycznie generowane hooki w naszych komponentach. Później opublikuję kolejne artykuły wyjaśniające bardziej zaawansowane funkcje i koncepcje zapytań rtk, takie jak buforowanie , pobieranie konfiguracji , przekształcanie danych itp.
Pełna baza kodu wszystkiego, co omówiliśmy, jest opublikowana w tym repozytorium i wdrożona na tej stronie .
Jeśli masz jakieś rekomendacje lub sugestie, nie wahaj się zapytać mnie przez moją prywatną pocztę lub dodać komentarz, a jeśli podobał Ci się ten artykuł, nie zapomnij o klaskaniu!
Więcej treści na PlainEnglish.io .
Zapisz się do naszego bezpłatnego cotygodniowego biuletynu . Śledź nas na Twitterze , LinkedIn , YouTube i Discordzie .
Zainteresowany skalowaniem startupu oprogramowania ? Sprawdź obwód .

![Czym w ogóle jest lista połączona? [Część 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)



































