Tingkatkan lapisan layanan Anda di proyek redux-toolkit Anda

Cara Membangun Aplikasi React dengan RTK-QUERY

Panduan pemula untuk menulis kueri dengan rtk-query

Tidak mungkin menjadi pengembang Front end yang bekerja dengan React dan belum pernah mendengar tentang redux dalam hidup Anda. Sebagian besar perusahaan menggunakan redux dalam basis kode mereka dan mengetahui konsep dasarnya telah menjadi salah satu esensi menjadi Frontender. Ada banyak diskusi tentang menggunakan atau tidak menggunakannya dalam produk Anda. Faktanya adalah, Anda tidak akan pernah bisa menemukan alat yang sempurna untuk semua proyek. Anda harus memutuskan alat mana yang paling sesuai dengan tujuan dan produk Anda. Meskipun terdapat kelebihan dan kekurangan pada masing-masing alat, hal terpenting adalah keseimbangan antara manfaat dan kerugian alat tersebut bagi ANDA.

Kueri RTK adalah alat pengambilan dan penyimpanan data yang canggih. Ini dirancang untuk menyederhanakan kasus umum untuk memuat data dalam aplikasi web, menghilangkan kebutuhan untuk menulis sendiri logika pengambilan data & cache.

Jika Anda menggunakan redux, khususnya redux-toolkit, Anda sudah tahu bahwa rtk-query hadir sebagai ketergantungan bawaan dengannya. Ada banyak alat serupa seperti react-query di luar sana, tetapi ketika Anda menggunakan redux-toolkit, dan sudah memiliki rtk-query di bundel Anda, mengapa tidak menggunakannya? Beberapa manfaat dari trk-query adalah:

  • Ini sepenuhnya kompatibel dengan redux
  • Ditulis dalam TypeScript
  • Tingkatkan lapisan layanan Anda agar lebih dapat digunakan kembali dan bawa proyek Anda dengan kait yang dibuat secara otomatis ke tingkat berikutnya
  • Ini dapat dilacak dan diamati melalui redux-devtools
  • Ini memiliki perilaku caching yang sangat bagus

Pada artikel ini, saya akan membantu Anda membuat aplikasi React blog sederhana dengan rtk-query dan TypeScript agar Anda lebih mengenal alat hebat ini. Aplikasi ini terdiri dari tampilan untuk menampilkan daftar postingan dan form sederhana untuk menambahkan postingan.

Prasyarat

  1. Anda harus mengetahui Reaksi
  2. Anda harus mengetahui konsep redux dan redux-toolkit dan ingin menggunakannya dalam proyek Anda
  3. Memiliki pengalaman dengan TypeScript merupakan nilai tambah, namun Anda cukup menghapus bagian TS dari kode dan itu akan berfungsi dengan JavaScript untuk Anda :)

Anda dapat menemukan repositori dan semua kode yang saya sebutkan di artikel ini di sini. Versi langsung dari tugas akhir dapat ditemukan di sini. Saya juga melewatkan penjelasan gaya atau bagian JSX sederhana karena topik utama di sini adalah rtk-query.

Bagaimana cara kerjanya?

Seperti yang saya sebutkan sebelumnya, rtk-query adalah alat pengambilan yang menyediakan banyak fitur untuk membuat proyek Anda lebih bersih dan dapat digunakan kembali. Layanan Anda dapat dibuat dalam bentuk endpoint dan kueri dengan menggunakan createApi yang sangat mirip dengan createReducer. Ini menghasilkan kaitan untuk pertanyaan Anda dan Anda dapat menggunakannya dengan mudah di komponen Anda. Anda tidak memerlukan status pemuatan, penanganan kesalahan, pengambilan ulang fungsi, pengambilan awal dengan useEffect, dan pengurai data lagi karena rtk-query akan mengurusnya untuk Anda.

Faktanya, kueri adalah bagian terkecil dari layanan Anda yang dapat berupa GET atau POST untuk mendapatkan atau mengirim data ke server. Semua kueri yang terkait dengan suatu entitas dikemas dalam satu titik akhir yang dibuat oleh createApi. Pada akhirnya, lapisan layanan Anda adalah kombinasi dari titik akhir yang berbeda termasuk kuerinya sendiri.

rtk-query menggunakan API pengambilan dari JavaScript. Namun Anda dapat mengonfigurasinya untuk menggunakan axios atau graphql. Selain itu, ini membungkus kueri Anda dengan "immer" sehingga mutasi data tidak lagi menjadi masalah.

Membangun fondasi

Anda dapat memilih alat APA SAJA dan pengaturan yang Anda suka untuk proyek ini. Saya akan menggunakan Vite, tetapi tidak masalah jika Anda lebih menyukai CRA atau Anda lebih suka mengonfigurasi boilerplate Anda sendiri. Setelah membuat proyek React, kita harus menginstal redux-toolkit + axios dan mengkonfigurasinya:

npm install @reduxjs/toolkit react-redux axios

Pertama, kita harus membuat fungsi kueri dasar untuk mengonfigurasi rtk-query agar menggunakan aksio:

// 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,
      };
    }
  };

BaseQueryFn adalah janji yang seharusnya menyelesaikan permintaan kita dengan beberapa data atau menolaknya dengan objek kesalahan. Di sini, kami menerima konfigurasi permintaan sederhana axios dari kueri kami dan melakukan pengambilan API dengan axios. Kemudian kami akan mengembalikan data jika semuanya baik-baik saja. Jika tidak, kami menolaknya dengan objek error. Pastikan untuk mengembalikan data atau kesalahan pada suatu objek, jika tidak, rtk-query tidak akan memahaminya.

Kami akan menggunakan API gratis JSONPlaceholder dalam proyek ini.

Kedua, kita harus memberi tahu rtk-query, untuk menggunakan fungsi kueri khusus kita alih-alih JS mengambil API. Hal ini dapat dilakukan dengan meneruskan fungsi kita ke createApi.

// src/services/api.ts

export const apiService = createApi({
  baseQuery: axiosBaseQuery(),
  endpoints: () => ({}),
});

Sekarang, kita cukup menambahkan kueri kita ke titik akhir. Tapi seperti yang Anda lihat, kami mengembalikan objek kosong. Alasannya adalah di dunia nyata, kami tidak ingin semua layanan kami ada dalam satu file yang panjang dan berantakan. Kami ingin membaginya menjadi beberapa modul kecil untuk mendapatkan basis kode yang lebih bersih. Jadi, kita mengembalikan objek kosong dan cukup menyuntikkan endpoint kita ke objek ini nanti.

Terakhir, kita perlu menambahkan apiService ke redux store dan menambahkan store tersebut ke aplikasi kita:

// 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>

Mengapa? apiService juga berisi peredam irisan Redux yang dibuat secara otomatis dan middleware khusus yang mengelola masa berlangganan. Keduanya perlu ditambahkan ke toko Redux

Membangun layanan pertama kami

Kita mulai dengan endpoint GET untuk mengambil daftar postingan dari server. Kita cukup menggunakan API injectEndpoint dari rtk-query, untuk membuat endpoint dan menambahkannya ke lapisan layanan dasar.

// 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;

endpoints adalah fungsi dengan satu argumen wajib — build — yang mengembalikan objek kueri yang berbeda. build adalah utilitas yang membantu Anda membuat endpoint dengan menggunakan konstruktor berbeda.build.query harus digunakan untuk GET endpoint dan build.mutation harus digunakan untuk endpoint lain seperti POST dan PATCH. Ini sedikit mirip dengan apa yang kita miliki di graphql. Konstruktor ini menerima objek yang memiliki satu argumen wajib yaitu query. query dengan kata sederhana adalah fungsi yang Anda gunakan untuk mengambil API dan harus mengembalikan konfigurasi permintaan aksio Anda seperti metode, params, dan url.

Kemudian, rtk-query membuat kaitan agar Anda dapat mengambil kueri ini dengan mudah. Anda dapat meneruskan lebih banyak setelan ke konstruktor kueri Anda seperti transformResponse yang tidak kami bahas karena berada di luar cakupan artikel ini.

Ayo gunakan layanan pertama kami

Sekarang saatnya menggunakan layanan kami. rtk-query menghasilkan kait useGetPostsQuery untuk kita. Kait ini mengembalikan objek yang terdiri dari beberapa nilai berguna untuk digunakan. Seperti status pemuatan, kesalahan, data yang dikembalikan, dan fungsi pengambilan ulang.

  • Status pemuatan: Statusnya akan benar saat kita menjalankan kueri ini di komponen kita.
  • Objek kesalahan: Jika kueri kami gagal, objek kesalahan akan dikembalikan, Jika tidak maka null.
  • data:Data yang kami kembalikan. Nilainya null hingga kueri kita berhasil dijalankan.
  • fungsi pengambilan ulang:Kita dapat menggunakan fungsi ini untuk menjalankan kembali kueri kapan pun diperlukan. Misalnya, jika kita ingin memiliki tombol “Coba lagi” atau segarkan.
// 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;

Hook useQuery mengambil API kita pada pemasangan komponen untuk pertama kalinya. Kita dapat mengontrolnya secara manual dengan menggunakan useLazyQuery. Seperti yang bisa Anda lihat, komponen kita sekarang jauh lebih bersih dan kita belum menggunakan useEffect atau useState apa pun di komponen kita.

Mari kita buat formulir kita

Untuk melangkah lebih jauh, mari kita bahas juga satu kueri mutasi. Kami ingin membuat postingan menggunakan formulir yang mendapat judul dan isi dari pengguna. Mari kita mulai dengan kueri itu sendiri:

// 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;

Dibandingkan dengan endpoint GET, kami memiliki 2 perbedaan di sini:

  1. Karena kita ingin menambahkan beberapa data dengan metode POST, kita menggunakan build.mutation daripada build.query.
  2. Kami menentukan antarmuka baru untuk argumen titik akhir kami dan meneruskan data yang sesuai ke permintaan aksio kami.

Sekarang kita harus menggunakan layanan baru ini di komponen formulir kita:

// 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;

Kait useMutation mengembalikan tupel. Item pertama dari array ini adalah mengambil API yang dapat Anda panggil dengan argumen tertentu. Item kedua adalah objek yang terdiri dari beberapa nilai penting seperti status pemuatan. Ini juga mengembalikan objek kesalahan yang dapat kita gunakan untuk menampilkan kesalahan jika pengiriman data gagal.

Bungkus itu

Kami telah membahas konsep dasar terpenting dari rtk-query. Kami melihat bagaimana kami dapat membuat layanan dan titik akhir kami secara modular dan bagaimana menggunakan kait fantastis yang dibuat secara otomatis di komponen kami. Nanti, saya akan menerbitkan artikel lanjutan yang menjelaskan fitur dan konsep kueri rtk yang lebih canggih seperti caching, pengambilan konfigurasi, transformasi data, dll.

Basis kode lengkap dari semua yang telah kami bahas dipublikasikan di repositori ini dan diterapkan di halaman ini.

Jika Anda mempunyai rekomendasi atau saran, jangan ragu untuk bertanya kepada saya melalui surat pribadi saya atau tambahkan komentar dan jika Anda menyukai artikel ini, jangan lupa bertepuk tangan!

Konten lainnya di PlainEnglish.io.

Daftar ke buletin mingguan gratis kami. Ikuti kami di "Twitter", "LinkedIn", "YouTube", dan "Discord" .

Tertarik untuk meningkatkan skala startup perangkat lunak Anda? Lihat "Sirkuit".