Mengatur TypeScript Untuk Proyek React Modern Menggunakan Webpack
Diterbitkan: 2022-03-10Di era pengembangan perangkat lunak ini, JavaScript dapat digunakan untuk mengembangkan hampir semua jenis aplikasi. Namun, fakta bahwa JavaScript diketik secara dinamis dapat menjadi perhatian bagi sebagian besar perusahaan perusahaan besar, karena fitur pengecekan tipe yang longgar.
Untungnya, kita tidak perlu menunggu sampai Ecma Technical Committee 39 memperkenalkan sistem tipe statis ke dalam JavaScript. Kita bisa menggunakan TypeScript sebagai gantinya.
JavaScript, yang diketik secara dinamis, tidak mengetahui tipe data variabel sampai variabel itu dipakai saat runtime. Pengembang yang menulis program perangkat lunak besar mungkin memiliki kecenderungan untuk menetapkan kembali variabel, yang dideklarasikan sebelumnya, ke nilai jenis yang berbeda, tanpa peringatan atau masalah apa pun, yang mengakibatkan bug sering diabaikan.
Dalam tutorial ini, kita akan mempelajari apa itu TypeScript dan bagaimana bekerja dengannya dalam proyek React. Pada akhirnya, kita akan membangun sebuah proyek yang terdiri dari aplikasi pemilih episode untuk acara TV Money Heist , menggunakan TypeScript dan kait mirip React saat ini ( useState
, useEffect
, useReducer
, useContext
). Dengan pengetahuan ini, Anda dapat terus bereksperimen dengan TypeScript di proyek Anda sendiri.
Artikel ini bukan pengantar TypeScript. Oleh karena itu, kita tidak akan membahas sintaks dasar TypeScript dan JavaScript. Namun, Anda tidak harus menjadi ahli dalam salah satu bahasa ini untuk mengikuti, karena kami akan mencoba mengikuti prinsip KISS (tetap sederhana, bodoh).
Apa itu TypeScript?
Pada tahun 2019, TypeScript menduduki peringkat bahasa ketujuh yang paling banyak digunakan dan bahasa dengan pertumbuhan tercepat kelima di GitHub. Tapi apa sebenarnya TypeScript itu?
Menurut dokumentasi resmi, TypeScript adalah superset JavaScript yang diketik yang dikompilasi ke JavaScript biasa. Ini dikembangkan dan dikelola oleh Microsoft dan komunitas sumber terbuka.
"Superset" dalam konteks ini berarti bahwa bahasa tersebut berisi semua fitur dan fungsionalitas JavaScript dan beberapa lainnya. TypeScript adalah bahasa script yang diketik.
Ini menawarkan pengembang lebih banyak kontrol atas basis kode mereka melalui anotasi jenis, kelas, dan antarmuka, sehingga pengembang tidak perlu memperbaiki bug yang mengganggu secara manual di konsol.
TypeScript tidak dibuat untuk mengubah JavaScript. Sebaliknya, ia memperluas JavaScript dengan fitur-fitur baru yang berharga. Program apa pun yang ditulis dalam JavaScript biasa juga akan berjalan seperti yang diharapkan di TypeScript, termasuk aplikasi seluler lintas platform dan back end di Node.js.
Ini berarti Anda juga dapat menulis aplikasi React di TypeScript, seperti yang akan kita lakukan dalam tutorial ini.
Mengapa TypeScript?
Mungkin, Anda tidak yakin untuk menerima kebaikan TypeScript. Mari kita pertimbangkan beberapa keuntungannya.
Lebih sedikit Bug
Kami tidak dapat menghilangkan semua bug dalam kode kami, tetapi kami dapat menguranginya. TypeScript memeriksa jenis pada waktu kompilasi dan melempar kesalahan jika jenis variabel berubah.
Mampu menemukan kesalahan yang jelas namun sering ini sejak awal membuatnya jauh lebih mudah untuk mengelola kode Anda dengan tipe.
Memfaktorkan Ulang Lebih Mudah
Anda mungkin sering ingin memfaktorkan ulang cukup banyak hal, tetapi karena mereka menyentuh begitu banyak kode lain dan banyak file lain, Anda berhati-hati untuk memodifikasinya.
Di TypeScript, hal-hal seperti itu seringkali dapat di-refactored hanya dengan mengklik perintah "Ganti nama simbol" di lingkungan pengembangan terintegrasi (IDE) Anda.
Dalam bahasa yang diketik secara dinamis seperti JavaScript, satu-satunya cara untuk memfaktorkan ulang banyak file secara bersamaan adalah dengan fungsi "cari dan ganti" tradisional menggunakan ekspresi reguler (RegExp).
Dalam bahasa yang diketik secara statis seperti TypeScript, "cari dan ganti" tidak diperlukan lagi. Dengan perintah IDE seperti "Temukan semua kemunculan" dan "Ganti nama simbol", Anda dapat melihat semua kemunculan di aplikasi dari fungsi, kelas, atau properti yang diberikan dari antarmuka objek.
TypeScript akan membantu Anda menemukan semua contoh bit refactored, mengganti namanya, dan mengingatkan Anda dengan kesalahan kompilasi jika kode Anda memiliki jenis ketidakcocokan setelah refactoring.
TypeScript bahkan memiliki lebih banyak keuntungan daripada yang telah kita bahas di sini.
Kekurangan TypeScript
TypeScript tentu bukan tanpa kekurangannya, bahkan dengan fitur-fitur menjanjikan yang disorot di atas.
Rasa Aman Palsu
Fitur pengecekan tipe TypeScript sering kali menciptakan rasa aman yang salah di antara pengembang. Pengecekan tipe memang memperingatkan kita ketika ada yang salah dengan kode kita. Namun, tipe statis tidak mengurangi kepadatan bug secara keseluruhan.
Oleh karena itu, kekuatan program Anda akan bergantung pada penggunaan TypeScript, karena tipe ditulis oleh pengembang dan tidak diperiksa saat runtime.
Jika Anda mencari TypeScript untuk mengurangi bug Anda, harap pertimbangkan pengembangan berbasis pengujian sebagai gantinya.
Sistem Pengetikan yang Rumit
Sistem pengetikan, meskipun merupakan alat yang hebat dalam banyak hal, terkadang bisa sedikit rumit. Kelemahan ini berasal dari interoperabilitas sepenuhnya dengan JavaScript, yang menyisakan lebih banyak ruang untuk komplikasi.
Namun, TypeScript masih JavaScript, jadi memahami JavaScript itu penting.
Kapan Menggunakan TypeScript?
Saya akan menyarankan Anda untuk menggunakan TypeScript dalam kasus berikut:
- Jika Anda ingin membangun aplikasi yang akan dipelihara dalam jangka waktu yang lama , maka saya sangat menyarankan untuk memulai dengan TypeScript, karena ini mendorong kode yang mendokumentasikan diri sendiri, sehingga membantu pengembang lain untuk memahami kode Anda dengan mudah saat mereka bergabung dengan basis kode Anda. .
- Jika Anda perlu membuat library , pertimbangkan untuk menulisnya di TypeScript. Ini akan membantu editor kode untuk menyarankan jenis yang sesuai untuk pengembang yang menggunakan perpustakaan Anda.
Dalam beberapa bagian terakhir, kami telah menyeimbangkan pro dan kontra dari TypeScript. Mari beralih ke bisnis hari ini: menyiapkan TypeScript di proyek React modern .
Mulai
Ada beberapa cara untuk mengatur TypeScript dalam Proyek Bereaksi. Dalam tutorial ini, kita hanya akan membahas dua.
Metode 1: Buat Aplikasi React + TypeScript
Sekitar dua tahun lalu, tim React merilis Create React App 2.1, dengan dukungan TypeScript. Jadi, Anda mungkin tidak perlu melakukan pekerjaan berat apa pun untuk memasukkan TypeScript ke dalam proyek Anda.
Untuk memulai proyek Create React App baru, Anda dapat menjalankan ini…
npx create-react-app my-app --folder-name
… atau ini:
yarn create react-app my-app --folder-name
Untuk menambahkan TypeScript ke proyek Create React App, pertama-tama instal dan masing-masing @types
:
npm install --save typescript @types/node @types/react @types/react-dom @types/jest
… atau:
yarn add typescript @types/node @types/react @types/react-dom @types/jest
Selanjutnya, ganti nama file (misalnya, index.js
menjadi index.tsx
), dan mulai ulang server pengembangan Anda !
Itu cepat, bukan?
Metode 2: Mengatur TypeScript Dengan Webpack
Webpack adalah bundler modul statis untuk aplikasi JavaScript. Dibutuhkan semua kode dari aplikasi Anda dan membuatnya dapat digunakan di browser web. Modul adalah potongan kode yang dapat digunakan kembali yang dibuat dari JavaScript, node_modules
, gambar, dan gaya CSS aplikasi Anda, yang dikemas agar mudah digunakan di situs web Anda.
Buat Proyek Baru
Mari kita mulai dengan membuat direktori baru untuk proyek kita:
mkdir react-webpack cd react-webpack
Kami akan menggunakan npm untuk menginisialisasi proyek kami:
npm init -y
Perintah di atas akan menghasilkan file package.json
dengan beberapa nilai default. Mari tambahkan juga beberapa dependensi untuk webpack, TypeScript, dan beberapa modul khusus React.
Menginstal Paket
Terakhir, kita perlu menginstal paket yang diperlukan. Buka antarmuka baris perintah (CLI) Anda dan jalankan ini:
#Installing devDependencies npm install --save-dev @types/react @types/react-dom awesome-typescript-loader css-loader html-webpack-plugin mini-css-extract-plugin source-map-loader typescript webpack webpack-cli webpack-dev-server #installing Dependencies npm install react react-dom
Mari kita juga menambahkan beberapa file dan folder berbeda secara manual di bawah folder react-webpack
kita:
- Tambahkan
webpack.config.js
untuk menambahkan konfigurasi terkait webpack. - Tambahkan
tsconfig.json
untuk semua konfigurasi TypeScript kami. - Tambahkan direktori baru,
src
. - Buat direktori baru,
components
, di foldersrc
. - Terakhir, tambahkan
index.html
,App.tsx
, danindex.tsx
di foldercomponents
.
Struktur Proyek
Dengan demikian, struktur folder kita akan terlihat seperti ini:
├── package.json ├── package-lock.json ├── tsconfig.json ├── webpack.config.js ├── .gitignore └── src └──components ├── App.tsx ├── index.tsx ├── index.html
Mulai Menambahkan Beberapa Kode
Kita akan mulai dengan index.html
:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>React-Webpack Setup</title> </head> <body> <div></div> </body> </html>
Ini akan membuat HTML, dengan div
kosong dengan ID output
.
Mari tambahkan kode ke komponen React kita App.tsx
:
import * as React from "react"; export interface HelloWorldProps { userName: string; lang: string; } export const App = (props: HelloWorldProps) => ( <h1> Hi {props.userName} from React! Welcome to {props.lang}! </h1> );
Kami telah membuat objek antarmuka dan menamakannya HelloWorldProps
, dengan userName
dan lang
memiliki tipe string
.
Kami meneruskan props
ke komponen App
kami dan mengekspornya.
Sekarang, mari kita perbarui kode di index.tsx
:
import * as React from "react"; import * as ReactDOM from "react-dom"; import { App } from "./App"; ReactDOM.render( <App userName="Beveloper" lang="TypeScript" />, document.getElementById("output") );
Kami baru saja mengimpor komponen App
ke index.tsx
. Ketika webpack melihat file apa pun dengan ekstensi .ts
atau .tsx
, itu akan mengubah file tersebut menggunakan library awesome-typescript-loader.
Konfigurasi TypeScript
Kami kemudian akan menambahkan beberapa konfigurasi ke tsconfig.json
:
{ "compilerOptions": { "jsx": "react", "module": "commonjs", "noImplicitAny": true, "outDir": "./build/", "preserveConstEnums": true, "removeComments": true, "sourceMap": true, "target": "es5" }, "include": [ "src/components/index.tsx" ] }
Mari kita lihat juga berbagai opsi yang kami tambahkan ke tsconfig.json
:
-
compilerOptions
Mewakili opsi compiler yang berbeda. -
jsx:react
Menambahkan dukungan untuk JSX dalam file.tsx
. -
lib
Menambahkan daftar file perpustakaan ke kompilasi (misalnya, menggunakanes2015
memungkinkan kita untuk menggunakan sintaks ECMAScript 6). -
module
Menghasilkan kode modul. -
noImplicitAny
Menimbulkan kesalahan untuk deklarasi dengan tipeany
yang tersirat. -
outDir
Mewakili direktori keluaran. -
sourceMap
Menghasilkan file.map
, yang bisa sangat berguna untuk men-debug aplikasi. -
target
Mewakili versi ECMAScript target untuk mengubah kode kita menjadi (kita dapat menambahkan versi berdasarkan kebutuhan browser spesifik kita). -
include
Digunakan untuk menentukan daftar file yang akan disertakan.
Konfigurasi Paket Web
Mari tambahkan beberapa konfigurasi webpack ke webpack.config.js
.
const path = require("path"); const HtmlWebpackPlugin = require("html-webpack-plugin"); const MiniCssExtractPlugin = require("mini-css-extract-plugin"); module.exports = { entry: "./src/components/index.tsx", target: "web", mode: "development", output: { path: path.resolve(\__dirname, "build"), filename: "bundle.js", }, resolve: { extensions: [".js", ".jsx", ".json", ".ts", ".tsx"], }, module: { rules: [ { test: /\.(ts|tsx)$/, loader: "awesome-typescript-loader", }, { enforce: "pre", test: /\.js$/, loader: "source-map-loader", }, { test: /\.css$/, loader: "css-loader", }, ], }, plugins: [ new HtmlWebpackPlugin({ template: path.resolve(\__dirname, "src", "components", "index.html"), }), new MiniCssExtractPlugin({ filename: "./src/yourfile.css", }), ], };
Mari kita lihat berbagai opsi yang telah kita tambahkan ke webpack.config.js
:
-
entry
Ini menentukan titik masuk untuk aplikasi kita. Ini mungkin file tunggal atau array file yang ingin kita sertakan dalam build. -
output
Ini berisi konfigurasi output. Aplikasi melihat ini ketika mencoba mengeluarkan kode yang dibundel dari proyek kami ke disk. Path mewakili direktori keluaran untuk kode yang akan dikeluarkan, dan nama file mewakili nama file yang sama. Biasanya bernamabundle.js
. -
resolve
Webpack melihat atribut ini untuk memutuskan apakah akan menggabungkan atau melewatkan file. Jadi, dalam proyek kami, webpack akan mempertimbangkan file dengan ekstensi.js
,.jsx
,.json
,.ts
, dan.tsx
untuk bundling. -
module
Kami dapat mengaktifkan webpack untuk memuat file tertentu saat diminta oleh aplikasi, menggunakan loader. Dibutuhkan objek aturan yang menentukan bahwa:- file apa pun yang diakhiri dengan ekstensi
.tsx
atau.ts
harus menggunakanawesome-typescript-loader
untuk dimuat; - file yang diakhiri dengan ekstensi
.js
harus dimuat dengansource-map-loader
; - file yang diakhiri dengan ekstensi
.css
harus dimuat dengancss-loader
.
- file apa pun yang diakhiri dengan ekstensi
-
plugins
Webpack memiliki keterbatasannya sendiri, dan menyediakan plugin untuk mengatasinya dan memperluas kemampuannya. Misalnya,html-webpack-plugin
membuat file template yang dirender ke browser dari fileindex.html
di direktori./src/component/index.html
.
MiniCssExtractPlugin
merender file CSS
induk aplikasi.
Menambahkan Script Ke package.json
Kami dapat menambahkan skrip yang berbeda untuk membangun aplikasi React di file package.json
kami:
"scripts": { "start": "webpack-dev-server --open", "build": "webpack" },
Sekarang, jalankan npm start
di CLI Anda. Jika semuanya berjalan dengan baik, Anda akan melihat ini:
Jika Anda memiliki kemampuan untuk webpack, klon repositori untuk pengaturan ini, dan gunakan di seluruh proyek Anda.
Membuat File
Buat folder src
dan file index.tsx
. Ini akan menjadi file dasar yang merender React.
Sekarang, jika kita menjalankan npm start
, itu akan menjalankan server kita dan membuka tab baru. Menjalankan npm run build
akan membangun webpack untuk produksi dan akan membuat folder build untuk kita.
Kita telah melihat cara mengatur TypeScript dari awal menggunakan metode Create React App dan konfigurasi webpack.
Salah satu cara tercepat untuk memahami sepenuhnya TypeScript adalah dengan mengonversi salah satu proyek Vanilla React Anda ke TypeScript. Sayangnya, secara bertahap mengadopsi TypeScript dalam proyek Vanilla React yang ada membuat stres karena mengharuskan harus mengeluarkan atau mengganti nama semua file, yang akan mengakibatkan konflik dan permintaan tarik raksasa jika proyek tersebut milik tim besar.
Selanjutnya, kita akan melihat cara mudah memigrasikan proyek React ke TypeScript.
Migrasikan Aplikasi Buat Bereaksi yang Ada Ke TypeScript
Untuk membuat proses ini lebih mudah dikelola, kami akan memecahnya menjadi beberapa langkah, yang akan memungkinkan kami untuk bermigrasi dalam potongan individu. Berikut adalah langkah-langkah yang akan kami ambil untuk memigrasikan proyek kami:
- Tambahkan TypeScript dan jenis.
- Tambahkan
tsconfig.json
. - Mulai dari yang kecil.
- Ganti nama ekstensi file menjadi
.tsx
.
1. Tambahkan TypeScript ke Proyek
Pertama, kita perlu menambahkan TypeScript ke proyek kita. Dengan asumsi bahwa proyek React Anda di-bootstrap dengan Create React App, kita dapat menjalankan yang berikut:
# Using npm npm install --save typescript @types/node @types/react @types/react-dom @types/jest # Using Yarn yarn add typescript @types/node @types/react @types/react-dom @types/jest
Perhatikan bahwa kami belum mengubah apa pun ke TypeScript. Jika kita menjalankan perintah untuk memulai proyek secara lokal ( npm start
atau yarn start
), tidak ada yang berubah. Jika itu masalahnya, maka bagus! Kami siap untuk langkah selanjutnya.
2. Tambahkan File tsconfig.json
Sebelum memanfaatkan TypeScript, kita perlu mengkonfigurasinya melalui file tsconfig.json
. Cara termudah untuk memulai adalah dengan membuat perancah menggunakan perintah ini:
npx tsc --init
Ini memberi kami beberapa dasar, dengan banyak kode yang dikomentari. Sekarang, ganti semua kode di tsconfig.json
dengan ini:
{ "compilerOptions": { "jsx": "react", "module": "commonjs", "noImplicitAny": true, "outDir": "./build/", "preserveConstEnums": true, "removeComments": true, "sourceMap": true, "target": "es5" }, "include": [ "./src/**/**/\*" ] }
Konfigurasi TypeScript
Mari kita lihat juga berbagai opsi yang kami tambahkan ke tsconfig.json
:
-
compilerOptions
Mewakili opsi compiler yang berbeda.-
target
Menerjemahkan konstruksi JavaScript yang lebih baru ke versi yang lebih lama, seperti ECMAScript 5. -
lib
Menambahkan daftar file perpustakaan ke kompilasi (misalnya, menggunakan es2015 memungkinkan kita untuk menggunakan sintaks ECMAScript 6). -
jsx:react
Menambahkan dukungan untuk JSX dalam file.tsx
. -
lib
Menambahkan daftar file perpustakaan ke kompilasi (misalnya, menggunakan es2015 memungkinkan kita untuk menggunakan sintaks ECMAScript 6). -
module
Menghasilkan kode modul. -
noImplicitAny
Digunakan untuk memunculkan kesalahan untuk deklarasi dengan tipeany
yang tersirat. -
outDir
Mewakili direktori keluaran. -
sourceMap
Menghasilkan file.map
, yang bisa sangat berguna untuk men-debug aplikasi kita. -
include
Digunakan untuk menentukan daftar file yang akan disertakan.
-
Opsi konfigurasi akan bervariasi, sesuai dengan permintaan proyek. Anda mungkin perlu memeriksa spreadsheet opsi TypeScript untuk mencari tahu apa yang sesuai dengan proyek Anda.
Kami hanya mengambil tindakan yang diperlukan untuk menyiapkan segalanya. Langkah kita selanjutnya adalah memigrasikan file ke TypeScript.
3. Mulai Dengan Komponen Sederhana
Manfaatkan kemampuan TypeScript untuk diadopsi secara bertahap. Buka satu file pada satu waktu dengan kecepatan Anda sendiri. Lakukan apa yang masuk akal bagi Anda dan tim Anda. Jangan mencoba untuk menangani semuanya sekaligus.
Untuk mengonversi ini dengan benar, kita perlu melakukan dua hal:
- Ubah ekstensi file menjadi
.tsx
. - Tambahkan anotasi tipe (yang akan membutuhkan pengetahuan TypeScript).
4. Ganti Nama Ekstensi File menjadi .tsx
Dalam basis kode yang besar, mungkin melelahkan untuk mengganti nama file satu per satu.
Ganti nama banyak file di macOS
Mengganti nama banyak file dapat membuang-buang waktu. Inilah cara Anda dapat melakukannya di Mac. Klik kanan (atau Ctrl
+ klik, atau klik dengan dua jari secara bersamaan di trackpad jika Anda menggunakan MacBook) pada folder yang berisi file yang ingin Anda ganti namanya. Kemudian, klik "Ungkapkan di Finder". Di Finder, pilih semua file yang ingin Anda ganti namanya. Klik kanan file yang dipilih, dan pilih "Ganti nama item X ..." Kemudian, Anda akan melihat sesuatu seperti ini:
Masukkan string yang ingin Anda temukan, dan string yang ingin Anda gunakan untuk mengganti string yang ditemukan, dan tekan "Ganti nama". Selesai.
Ganti nama banyak file di Windows
Mengganti nama banyak file di Windows berada di luar cakupan tutorial ini, tetapi panduan lengkap tersedia. Anda biasanya akan mendapatkan kesalahan setelah mengganti nama file; Anda hanya perlu menambahkan anotasi jenis. Anda dapat memoles ini di dokumentasi.
Kami telah membahas cara mengatur TypeScript di aplikasi React. Sekarang, mari buat aplikasi pemilih episode untuk Money Heist menggunakan TypeScript.
Kami tidak akan membahas tipe dasar TypeScript. Diperlukan melalui dokumentasi sebelum melanjutkan dalam tutorial ini.
Saatnya Membangun
Untuk membuat proses ini terasa tidak terlalu menakutkan, kita akan memecahnya menjadi beberapa langkah, yang akan memungkinkan kita untuk membangun aplikasi dalam potongan individu. Berikut adalah semua langkah yang akan kami ambil untuk membuat pemetik episode Money Heist :
- Scaffold pada Create React App.
- Ambil episode.
- Buat jenis dan antarmuka yang sesuai untuk episode kami di
interface.ts
. - Siapkan toko untuk mengambil episode di
store.tsx
. - Buat aksi untuk mengambil episode di
action.ts
. - Buat komponen
EpisodeList.tsx
yang menyimpan episode yang diambil. - Impor komponen
EpisodesList
ke halaman beranda kami menggunakanReact Lazy and Suspense
.
- Buat jenis dan antarmuka yang sesuai untuk episode kami di
- Tambahkan episode.
- Siapkan toko untuk menambahkan episode di
store.tsx
. - Buat aksi untuk menambahkan episode di
action.ts
.
- Siapkan toko untuk menambahkan episode di
- Hapus episode.
- Siapkan toko untuk menghapus episode di
store.tsx
. - Buat aksi untuk menghapus episode di
action.ts
.
- Siapkan toko untuk menghapus episode di
- Adegan favorit.
- Impor komponen
EpisodesList
di episode favorit. - Render
EpisodesList
di dalam episode favorit.
- Impor komponen
- Menggunakan Reach Router untuk navigasi.
Mengatur Reaksi
Cara termudah untuk mengatur React adalah dengan menggunakan Create React App. Create React App adalah cara yang didukung secara resmi untuk membuat aplikasi React satu halaman. Ini menawarkan pengaturan build modern tanpa konfigurasi.
Kita akan menggunakannya untuk bootstrap aplikasi yang akan kita bangun. Dari CLI Anda, jalankan perintah di bawah ini:
npx create-react-app react-ts-app && cd react-ts-app
Setelah instalasi berhasil, jalankan server React dengan menjalankan npm start
.
Memahami Antarmuka Dan Jenis Dalam TypeScript
Antarmuka dalam TypeScript digunakan ketika kita perlu memberikan tipe ke properti objek. Oleh karena itu, kami akan menggunakan antarmuka untuk mendefinisikan tipe kami.
interface Employee { name: string, role: string salary: number } const bestEmployee: Employee= { name: 'John Doe', role: 'IOS Developer', salary: '$8500' //notice we are using a string }
Saat mengkompilasi kode di atas, kita akan melihat kesalahan ini: “Jenis salary
properti tidak sesuai. Ketik string
tidak dapat ditetapkan untuk mengetikkan number
.”
Kesalahan seperti itu terjadi di TypeScript ketika properti atau variabel diberi tipe selain tipe yang ditentukan. Secara khusus, cuplikan di atas berarti bahwa properti salary
diberi tipe string
, bukan tipe number
.
Mari buat file interface.ts
di folder src
kita. Salin dan tempel kode ini ke dalamnya:
/** |-------------------------------------------------- | All the interfaces! |-------------------------------------------------- */ export interface IEpisode { airdate: string airstamp: string airtime: string id: number image: { medium: string; original: string } name: string number: number runtime: number season: number summary: string url: string } export interface IState { episodes: Array<IEpisode> favourites: Array<IEpisode> } export interface IAction { type: string payload: Array<IEpisode> | any } export type Dispatch = React.Dispatch<IAction> export type FavAction = ( state: IState, dispatch: Dispatch, episode: IEpisode ) => IAction export interface IEpisodeProps { episodes: Array<IEpisode> store: { state: IState; dispatch: Dispatch } toggleFavAction: FavAction favourites: Array<IEpisode> } export interface IProps { episodes: Array<IEpisode> store: { state: IState; dispatch: Dispatch } toggleFavAction: FavAction favourites: Array<IEpisode> }
Ini adalah praktik yang baik untuk menambahkan "I" ke nama antarmuka. Itu membuat kode dapat dibaca. Namun, Anda dapat memutuskan untuk mengecualikannya.
Antarmuka episode IE
API kami mengembalikan sekumpulan properti seperti airdate
, airstamp
, airtime
, id
, image
, name
, number
, runtime
, season
, summary
, dan url
. Oleh karena itu, kami mendefinisikan antarmuka IEpisode
dan mengatur tipe data yang sesuai ke properti objek.
Antarmuka Negara
Antarmuka IState
kami masing-masing memiliki properti episodes
dan favorites
, dan antarmuka Array<IEpisode>
.
tindakan IA
Properti antarmuka IAction
adalah payload
dan type
. Properti type
memiliki tipe string, sedangkan payload memiliki tipe Array | any
Array | any
Perhatikan bahwa Array | any
Array | any
berarti larik antarmuka episode atau jenis apa pun.
Jenis Dispatch
diatur ke React.Dispatch
dan antarmuka <IAction>
. Perhatikan bahwa React.Dispatch
adalah tipe standar untuk fungsi dispatch
, menurut basis kode @types/react
, sedangkan <IAction>
adalah larik tindakan Antarmuka.
Juga, Visual Studio Code memiliki pemeriksa TypeScript. Jadi, hanya dengan menyorot atau mengarahkan kursor ke kode, cukup pintar untuk menyarankan jenis yang sesuai.
Dengan kata lain, agar kami dapat menggunakan antarmuka kami di seluruh aplikasi kami, kami perlu mengekspornya. Sejauh ini, kami memiliki toko dan antarmuka kami yang menampung jenis objek kami. Sekarang mari kita buat toko kita. Perhatikan bahwa antarmuka lain mengikuti konvensi yang sama seperti yang dijelaskan.
Ambil Episode
Membuat Toko
Untuk mengambil episode kami, kami membutuhkan toko yang menyimpan status awal data dan yang mendefinisikan fungsi peredam kami.
Kami akan menggunakan kait useReducer
untuk mengaturnya. Buat file store.tsx
di folder src
Anda. Salin dan tempel kode berikut ke dalamnya.
import React, { useReducer, createContext } from 'react' import { IState, IAction } from './types/interfaces' const initialState: IState = { episodes: [], favourites: [] } export const Store = createContext (initialState) const reducer = (state: IState, action: IAction): IState => { switch (action.type) { case 'FETCH_DATA': return { ...state, episodes: action.payload } default: return state } } export const StoreProvider = ({ children }: JSX.ElementChildrenAttribute): JSX.Element => { const [state, dispatch] = useReducer(reducer, initialState) return {children} }
import React, { useReducer, createContext } from 'react' import { IState, IAction } from './types/interfaces' const initialState: IState = { episodes: [], favourites: [] } export const Store = createContext (initialState) const reducer = (state: IState, action: IAction): IState => { switch (action.type) { case 'FETCH_DATA': return { ...state, episodes: action.payload } default: return state } } export const StoreProvider = ({ children }: JSX.ElementChildrenAttribute): JSX.Element => { const [state, dispatch] = useReducer(reducer, initialState) return {children} }
import React, { useReducer, createContext } from 'react' import { IState, IAction } from './types/interfaces' const initialState: IState = { episodes: [], favourites: [] } export const Store = createContext (initialState) const reducer = (state: IState, action: IAction): IState => { switch (action.type) { case 'FETCH_DATA': return { ...state, episodes: action.payload } default: return state } } export const StoreProvider = ({ children }: JSX.ElementChildrenAttribute): JSX.Element => { const [state, dispatch] = useReducer(reducer, initialState) return {children} }
import React, { useReducer, createContext } from 'react' import { IState, IAction } from './types/interfaces' const initialState: IState = { episodes: [], favourites: [] } export const Store = createContext (initialState) const reducer = (state: IState, action: IAction): IState => { switch (action.type) { case 'FETCH_DATA': return { ...state, episodes: action.payload } default: return state } } export const StoreProvider = ({ children }: JSX.ElementChildrenAttribute): JSX.Element => { const [state, dispatch] = useReducer(reducer, initialState) return {children} }
Berikut ini adalah langkah-langkah yang kami lakukan untuk membuat toko:
- Dalam mendefinisikan toko kita, kita memerlukan kait
useReducer
dan APIcreateContext
dari React, itulah sebabnya kita mengimpornya. - Kami mengimpor
IState
danIAction
dari./types/interfaces
. - Kami mendeklarasikan objek
initialState
dengan tipeIState
, dan properti episode dan favorit, yang keduanya disetel ke array kosong, masing-masing. - Selanjutnya, kami membuat variabel
Store
yang menyimpan metodecreateContext
dan yang diteruskan denganinitialState
.
Jenis metode createContext
adalah <IState | any>
<IState | any>
, yang berarti bisa berupa jenis <IState>
atau any
. Kita akan melihat jenis any
yang sering digunakan dalam artikel ini.
- Selanjutnya, kami mendeklarasikan fungsi
reducer
dan meneruskanstate
danaction
sebagai parameter. Fungsireducer
memiliki pernyataan sakelar yang memeriksa nilaiaction.type
. Jika nilainya adalahFETCH_DATA
, maka ia mengembalikan objek yang memiliki salinan status kita(...state)
dan status episode yang menampung muatan tindakan kita. - Dalam pernyataan switch, kami mengembalikan status
default
.
Perhatikan bahwa parameter state
dan action
dalam fungsi peredam masing-masing memiliki tipe IState
dan IAction
. Juga, fungsi reducer
memiliki tipe IState
.
- Terakhir, kami mendeklarasikan fungsi
StoreProvider
. Ini akan memberikan semua komponen di aplikasi kami akses ke toko. - Fungsi ini mengambil
children
-anak sebagai penyangga, dan di dalam fungsiStorePrivder
, kami mendeklarasikan kaituseReducer
. - Kami merusak
state
dandispatch
. - Untuk membuat toko kami dapat diakses oleh semua komponen, kami memberikan nilai objek yang berisi
state
dandispatch
.
state
yang berisi episode dan status favorit kami akan dapat diakses oleh komponen lain, sedangkan dispatch
adalah fungsi yang mengubah status.
- Kami akan mengekspor
Store
danStoreProvider
, sehingga dapat digunakan di seluruh aplikasi kami.
Buat Action.ts
Kita harus membuat permintaan ke API untuk mengambil episode yang akan ditampilkan kepada pengguna. Ini akan dilakukan dalam file tindakan. Buat file Action.ts
, lalu tempel kode berikut:
import { Dispatch } from './interface/interfaces' export const fetchDataAction = async (dispatch: Dispatch) => { const URL = 'https://api.tvmaze.com/singlesearch/shows?q=la-casa-de-papel&embed=episodes' const data = await fetch(URL) const dataJSON = await data.json() return dispatch({ type: 'FETCH_DATA', payload: dataJSON.\_embedded.episodes }) }
Pertama, kita perlu mengimpor antarmuka kita agar dapat digunakan dalam file ini. Langkah-langkah berikut diambil untuk membuat tindakan:
- Fungsi
fetchDataAction
mengambil alat peragadispatch
sebagai parameter. - Karena fungsi kami tidak sinkron, kami akan menggunakan
async
danawait
. - Kami membuat variabel (
URL
) yang menyimpan titik akhir API kami. - Kami memiliki variabel lain bernama
data
yang menyimpan respons dari API. - Kemudian, kita menyimpan respon JSON di
dataJSON
, setelah kita mendapatkan respon dalam format JSON dengan memanggildata.json()
. - Terakhir, kami mengembalikan fungsi pengiriman yang memiliki properti
type
dan stringFETCH_DATA
. Ia juga memilikipayload()
._embedded.episodes
adalah larik objek episodes dariendpoint
kita .
Perhatikan bahwa fungsi fetchDataAction
mengambil titik akhir kita, mengonversinya menjadi objek JSON
, dan mengembalikan fungsi pengiriman, yang memperbarui status yang dideklarasikan sebelumnya di Store.
Jenis pengiriman yang diekspor diatur ke React.Dispatch
. Perhatikan bahwa React.Dispatch
adalah tipe standar untuk fungsi pengiriman menurut basis kode @types/react
, sedangkan <IAction>
adalah larik dari Tindakan Antarmuka.
Komponen Daftar Episode
Untuk mempertahankan kegunaan kembali aplikasi kami, kami akan menyimpan semua episode yang diambil dalam file terpisah, dan kemudian mengimpor file dalam homePage
halaman rumah kami.
Di folder components
, buat file EpisodesList.tsx
, dan salin dan tempel kode berikut ke dalamnya:
import React from 'react' import { IEpisode, IProps } from '../types/interfaces' const EpisodesList = (props: IProps): Array<JSX.Element> => { const { episodes } = props return episodes.map((episode: IEpisode) => { return ( <section key={episode.id} className='episode-box'> <img src={!!episode.image ? episode.image.medium : ''} alt={`Money Heist ${episode.name}`} /> <div>{episode.name}</div> <section style={{ display: 'flex', justifyContent: 'space-between' }}> <div> Season: {episode.season} Number: {episode.number} </div> <button type='button' > Fav </button> </section> </section> ) }) } export default EpisodesList
- Kami mengimpor
IEpisode
danIProps
dariinterfaces.tsx
. - Selanjutnya, kita membuat fungsi
EpisodesList
yang mengambil props. Alat peraga akan memiliki tipeIProps
, sedangkan fungsinya memiliki tipeArray<JSX.Element>
.
Visual Studio Code menyarankan agar tipe fungsi kita ditulis sebagai JSX.Element[]
.
Sementara Array<JSX.Element>
sama dengan JSX.Element[]
, Array<JSX.Element>
disebut identitas generik. Oleh karena itu, pola generik akan sering digunakan dalam artikel ini.
- Di dalam fungsi, kami merusak
episodes
dariprops
, yang memilikiIEpisode
sebagai tipe.
Baca tentang identitas generik, Pengetahuan ini akan dibutuhkan saat kita melanjutkan.
- Kami mengembalikan alat peraga
episodes
dan memetakannya untuk mengembalikan beberapa tag HTML. - Bagian pertama memegang
key
, yaituepisode.id
, danclassName
dariepisode-box
, yang akan dibuat nanti. Kami tahu bahwa episode kami memiliki gambar; karenanya, tag gambar. - Gambar memiliki operator ternary yang memeriksa apakah ada
episode.image
atauepisode.image.medium
. Lain, kami menampilkan string kosong jika tidak ada gambar yang ditemukan. Juga, kami menyertakanepisode.name
dalam div.
Di section
, kami menunjukkan musim tempat sebuah episode dan nomornya. Kami memiliki tombol dengan teks Fav
. Kami telah mengekspor komponen EpisodesList
sehingga kami dapat menggunakannya di seluruh aplikasi kami.
Komponen Halaman Beranda
Kami ingin halaman beranda memicu panggilan API dan menampilkan episode menggunakan komponen EpisodesList
yang kami buat. Di dalam folder components
, buat komponen HomePage
, dan salin dan tempel kode berikut ke dalamnya:
import React, { useContext, useEffect, lazy, Suspense } from 'react' import App from '../App' import { Store } from '../Store' import { IEpisodeProps } from '../types/interfaces' import { fetchDataAction } from '../Actions' const EpisodesList = lazy<any>(() => import('./EpisodesList')) const HomePage = (): JSX.Element => { const { state, dispatch } = useContext(Store) useEffect(() => { state.episodes.length === 0 && fetchDataAction(dispatch) }) const props: IEpisodeProps = { episodes: state.episodes, store: { state, dispatch } } return ( <App> <Suspense fallback={<div>loading...</div>}> <section className='episode-layout'> <EpisodesList {...props} /> </section> </Suspense> </App> ) } export default HomePage
- Kami mengimpor
useContext
,useEffect
,lazy
, danSuspense
dari React. Komponen aplikasi yang diimpor adalah landasan di mana semua komponen lain harus menerima nilai toko. - Kami juga mengimpor
Store
,IEpisodeProps
, danFetchDataAction
dari file masing-masing. - Kami mengimpor komponen
EpisodesList
menggunakan fiturReact.lazy
yang tersedia di React 16.6.
React lazy loading mendukung konvensi pemecahan kode. Dengan demikian, komponen EpisodesList
kami dimuat secara dinamis, bukannya dimuat sekaligus, sehingga meningkatkan kinerja aplikasi kami.
- Kami merusak
state
dandispatch
sebagai alat peraga dariStore
. - Ampersand (&&) di kait
useEffect
memeriksa apakah status episode kitaempty
(atau sama dengan 0). Jika tidak, kami mengembalikan fungsifetchDataAction
. - Terakhir, kami mengembalikan komponen
App
. Di dalamnya, kami menggunakan pembungkusSuspense
, dan mengaturfallback
ke div denganloading
teks. Ini akan ditampilkan kepada pengguna sementara kami menunggu tanggapan dari API. - Komponen
EpisodesList
akan dipasang ketika data tersedia, dan data yang akan berisiepisodes
itulah yang kami sebarkan ke dalamnya.
Siapkan Index.txs
Komponen Homepage
harus merupakan turunan dari StoreProvider
. Kita harus melakukannya di file index
. Ganti nama index.js
menjadi index.tsx
dan rekatkan kode berikut:
import React from 'react' import ReactDOM from 'react-dom' import './index.css' import { StoreProvider } from './Store' import HomePage from './components/HomePage' ReactDOM.render( <StoreProvider> <HomePage /> </StoreProvider>, document.getElementById('root') )
Kami mengimpor StoreProvider
, HomePage
, dan index.css
dari file masing-masing. We wrap the HomePage
component in our StoreProvider
. This makes it possible for the Homepage
component to access the store, as we saw in the previous section.
Kami telah datang jauh. Let's check what the app looks like, without any CSS.
Create Index.css
Delete the code in the index.css
file and replace it with this:
html { font-size: 14px; } body { margin: 0; padding: 0; font-size: 10px; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; } .episode-layout { display: flex; flex-wrap: wrap; min-width: 100vh; } .episode-box { padding: .5rem; } .header { display: flex; justify-content: space-between; background: white; border-bottom: 1px solid black; padding: .5rem; position: sticky; top: 0; }
Our app now has a look and feel. Here's how it looks with CSS.
Now we see that our episodes can finally be fetched and displayed, because we've adopted TypeScript all the way. Great, isn't it?
Add Favorite Episodes Feature
Let's add functionality that adds favorite episodes and that links it to a separate page. Let's go back to our Store component and add a few lines of code:
Note that the highlighted code is newly added:
import React, { useReducer, createContext } from 'react' import { IState, IAction } from './types/interfaces' const initialState: IState = { episodes: [], favourites: [] } export const Store = createContext<IState | any>(initialState) const reducer = (state: IState, action: IAction): IState => { switch (action.type) { case 'FETCH_DATA': return { ...state, episodes: action.payload }
case 'ADD_FAV': return { ...state, favourites: [...state.favourites, action.payload] }
default: return state } } export const StoreProvider = ({ children }: JSX.ElementChildrenAttribute): JSX.Element => { const [state, dispatch] = useReducer(reducer, initialState) return <Store.Provider value={{ state, dispatch }}>{children}</Store.Provider> }
To implement the “Add favorite” feature to our app, the ADD_FAV
case is added. It returns an object that holds a copy of our previous state, as well as an array with a copy of the favorite state
, with the payload
.
We need an action that will be called each time a user clicks on the FAV
button. Let's add the highlighted code to index.tx
:
import {
IAction, IEpisode, Dispatch } from './types/interfaces'
export const fetchDataAction = async (dispatch: Dispatch) => { const URL = 'https://api.tvmaze.com/singlesearch/shows?q=la-casa-de-papel&embed=episodes' const data = await fetch(URL) const dataJSON = await data.json() return dispatch({ type: 'FETCH_DATA', payload: dataJSON._embedded.episodes }) }
export const toggleFavAction = (dispatch: any, episode: IEpisode | any): IAction => { let dispatchObj = { type: 'ADD_FAV', payload: episode } return dispatch(dispatchObj) }
export const toggleFavAction = (dispatch: any, episode: IEpisode | any): IAction => { let dispatchObj = { type: 'ADD_FAV', payload: episode } return dispatch(dispatchObj) }
We create a toggleFavAction
function that takes dispatch
and episodes
as parameters, and any
and IEpisode|any
as their respective types, with IAction
as our function type. We have an object whose type
is ADD_FAV
and that has episode
as its payload. Lastly, we just return and dispatch the object.
Kami akan menambahkan beberapa cuplikan lagi ke EpisodeList.tsx
. Salin dan tempel kode yang disorot:
import React from 'react' import { IEpisode, IProps } from '../types/interfaces' const EpisodesList = (props: IProps): Array<JSX.Element> => {
const { episodes, toggleFavAction, favourites, store } = props const { state, dispatch } = store
return episodes.map((episode: IEpisode) => { return ( <section key={episode.id} className='episode-box'> <img src={!!episode.image ? episode.image.medium : ''} alt={`Money Heist - ${episode.name}`} /> <div>{episode.name}</div> <section style={{ display: 'flex', justifyContent: 'space-between' }}> <div> Seasion: {episode.season} Number: {episode.number} </div> <button type='button'
onClick={() => toggleFavAction(state, dispatch, episode)} > {favourites.find((fav: IEpisode) => fav.id === episode.id) ? 'Unfav' : 'Fav'}
</button> </section> </section> ) }) } export default EpisodesList
Kami menyertakan togglefavaction
, favorites
, dan store
sebagai props, dan kami merusak state
, dispatch
dari store. Untuk memilih episode favorit, kami menyertakan metode toggleFavAction
dalam acara onClick
, dan meneruskan props state
, dispatch
, dan episode
sebagai argumen ke fungsi tersebut.
Terakhir, kami mengulang status favorite
untuk memeriksa apakah fav.id
(ID favorit) cocok dengan episode.id
. Jika ya, kita beralih antara teks Unfav
dan Fav
. Ini membantu pengguna mengetahui apakah mereka telah memfavoritkan episode itu atau tidak.
Kami semakin dekat dengan akhir. Tetapi kami masih membutuhkan halaman tempat episode favorit dapat ditautkan saat pengguna memilih di antara episode di halaman beranda.
Jika Anda sudah sejauh ini, tepuk punggung Anda.
Komponen Favpage
Di folder components
, buat file FavPage.tsx
. Salin dan tempel kode berikut ke dalamnya:
import React, { lazy, Suspense } from 'react' import App from '../App' import { Store } from '../Store' import { IEpisodeProps } from '../types/interfaces' import { toggleFavAction } from '../Actions' const EpisodesList = lazy<any>(() => import('./EpisodesList')) export default function FavPage(): JSX.Element { const { state, dispatch } = React.useContext(Store) const props: IEpisodeProps = { episodes: state.favourites, store: { state, dispatch }, toggleFavAction, favourites: state.favourites } return ( <App> <Suspense fallback={<div>loading...</div>}> <div className='episode-layout'> <EpisodesList {...props} /> </div> </Suspense> </App> ) }
Untuk membuat logika di balik pemilihan episode favorit, kami telah menulis sedikit kode. Kami mengimpor lazy
dan Suspense
dari React. Kami juga mengimpor Store
, IEpisodeProps
, dan toggleFavAction
dari file masing-masing.
Kami mengimpor komponen EpisodesList
kami menggunakan fitur React.lazy
. Terakhir, kami mengembalikan komponen App
. Di dalamnya, kami menggunakan pembungkus Suspense
, dan mengatur fallback ke div dengan teks pemuatan.
Ini bekerja mirip dengan komponen Homepage
. Komponen ini akan mengakses toko untuk mendapatkan episode favorit pengguna. Kemudian, daftar episode diteruskan ke komponen EpisodesList
.
Mari tambahkan beberapa cuplikan lagi ke file HomePage.tsx
.
Sertakan toggleFavAction
dari ../Actions
. Sertakan juga metode toggleFavAction
sebagai props.
import React, { useContext, useEffect, lazy, Suspense } from 'react' import App from '../App' import { Store } from '../Store' import { IEpisodeProps } from '../types/interfaces'
import { fetchDataAction, toggleFavAction } from '../Actions'
const EpisodesList = lazy<any>(() => import('./EpisodesList')) const HomePage = (): JSX.Element => { const { state, dispatch } = useContext(Store) useEffect(() => { state.episodes.length === 0 && fetchDataAction(dispatch) }) const props: IEpisodeProps = { episodes: state.episodes, store: { state, dispatch },
toggleFavAction, favourites: state.favourites
} return ( <App> <Suspense fallback={<div>loading...</div>}> <section className='episode-layout'> <EpisodesList {...props} /> </section> </Suspense> </App> ) } export default HomePage
FavPage
kami perlu ditautkan, jadi kami memerlukan tautan di header kami di App.tsx
. Untuk mencapai ini, kami menggunakan Reach Router, sebuah library yang mirip dengan React Router. William Le menjelaskan perbedaan antara Reach Router dan React Router.
Di CLI Anda, jalankan npm install @reach/router @types/reach__router
. Kami memasang kedua jenis perpustakaan Reach Router dan reach-router
.
Setelah instalasi berhasil, impor Link
dari @reach/router
.
import React, { useContext, Fragment } from 'react' import { Store } from './tsx'
import { Link } from '@reach/router'
const App = ({ children }: { children: JSX.Element }): JSX.Element => {
const { state } = useContext(Store)
return ( <Fragment> <header className='header'> <div> <h1>Money Heist</h1> <p>Pick your favourite episode</p> </div>
<div> <Link to='/'>Home</Link> <Link to='/faves'>Favourite(s): {state.favourites.length}</Link> </div>
</header> {children} </Fragment> ) } export default App
Kami merusak toko dari useContext
. Terakhir, rumah kita akan memiliki Link
dan jalur ke /
, sedangkan favorit kita memiliki jalur ke /faves
.
{state.favourites.length}
memeriksa jumlah episode di status favorit dan menampilkannya.
Terakhir, dalam file index.tsx
, kita mengimpor komponen FavPage
dan HomePage
masing-masing, dan membungkusnya di Router
.
Salin kode yang disorot ke kode yang ada:
import React from 'react' import ReactDOM from 'react-dom' import './index.css' import { StoreProvider } from './Store'
import { Router, RouteComponentProps } from '@reach/router' import HomePage from './components/HomePage' import FavPage from './components/FavPage' const RouterPage = ( props: { pageComponent: JSX.Element } & RouteComponentProps ) => props.pageComponent
ReactDOM.render( <StoreProvider>
<Router> <RouterPage pageComponent={<HomePage />} path='/' /> <RouterPage pageComponent={<FavPage />} path='/faves' /> </Router>
</StoreProvider>, document.getElementById('root') )
Sekarang, mari kita lihat bagaimana ADD_FAV
yang diimplementasikan bekerja.
Hapus Fungsi Favorit
Terakhir, kami akan menambahkan fitur "Hapus episode", sehingga ketika tombol diklik, kami beralih antara menambahkan atau menghapus episode favorit. Kami akan menampilkan jumlah episode yang ditambahkan atau dihapus di header.
TOKO
Untuk membuat fungsi "Hapus episode favorit", kami akan menambahkan kasing lain di toko kami. Jadi, buka Store.tsx
dan tambahkan kode yang disorot:
import React, { useReducer, createContext } from 'react' import { IState, IAction } from './types/interfaces' const initialState: IState = { episodes: [], favourites: [] } export const Store = createContext<IState | any>(initialState) const reducer = (state: IState, action: IAction): IState => { switch (action.type) { case 'FETCH_DATA': return { ...state, episodes: action.payload } case 'ADD_FAV': return { ...state, favourites: [...state.favourites, action.payload] }
case 'REMOVE_FAV': return { ...state, favourites: action.payload }
default: return state } } export const StoreProvider = ({ children }: JSX.ElementChildrenAttribute): JSX.Element => { const [state, dispatch] = useReducer(reducer, initialState) return {children} }
default: return state } } export const StoreProvider = ({ children }: JSX.ElementChildrenAttribute): JSX.Element => { const [state, dispatch] = useReducer(reducer, initialState) return {children} }
default: return state } } export const StoreProvider = ({ children }: JSX.ElementChildrenAttribute): JSX.Element => { const [state, dispatch] = useReducer(reducer, initialState) return {children} }
Kami menambahkan kasus lain bernama REMOVE_FAV
dan mengembalikan objek yang berisi salinan initialState
kami. Juga, status favorites
berisi muatan aksi.
TINDAKAN
Salin kode yang disorot berikut dan tempel di action.ts
:
import
{ IAction, IEpisode, IState, Dispatch } from './types/interfaces'
export const fetchDataAction = async (dispatch: Dispatch) => { const URL = 'https://api.tvmaze.com/singlesearch/shows?q=la-casa-de-papel&embed=episodes' const data = await fetch(URL) const dataJSON = await data.json() return dispatch({ type: 'FETCH_DATA', payload: dataJSON.\_embedded.episodes }) } //Add IState withits type
export const toggleFavAction = (state: IState, dispatch: any, episode: IEpisode | any): IAction => { const episodeInFav = state.favourites.includes(episode)
let dispatchObj = { type: 'ADD_FAV', payload: episode }
if (episodeInFav) { const favWithoutEpisode = state.favourites.filter( (fav: IEpisode) => fav.id !== episode.id ) dispatchObj = { type: 'REMOVE_FAV', payload: favWithoutEpisode }
} return dispatch(dispatchObj) }
Kami mengimpor antarmuka IState
dari ./types/interfaces
, karena kami harus meneruskannya sebagai tipe ke properti state
dalam fungsi toggleFavAction
.
Variabel episodeInFav
dibuat untuk memeriksa apakah ada episode yang ada dalam status favorites
.
Kami memfilter status favorit untuk memeriksa apakah ID favorit tidak sama dengan ID episode. Dengan demikian, dispatchObj
ditugaskan kembali jenis REMOVE_FAV
dan muatan favWithoutEpisode
.
Mari kita lihat hasil dari aplikasi kita.
Kesimpulan
Dalam artikel ini, kita telah melihat cara mengatur TypeScript dalam proyek React, dan cara memigrasikan proyek dari vanilla React ke TypeScript.
Kami juga telah membuat aplikasi dengan TypeScript dan React untuk melihat bagaimana TypeScript digunakan dalam proyek React. Saya percaya Anda dapat mempelajari beberapa hal.
Silakan bagikan umpan balik dan pengalaman Anda dengan TypeScript di bagian komentar di bawah. Saya ingin melihat apa yang Anda dapatkan!
Repositori pendukung untuk artikel ini tersedia di GitHub.
Referensi
- “Cara Migrasi Aplikasi React Ke TypeScript,” Joe Previte
- “Mengapa Dan Bagaimana Cara Menggunakan TypeScript di Aplikasi React Anda?,” Mahesh Haldar