Web Paketi Kullanarak Modern React Projeleri İçin TypeScript Ayarlama
Yayınlanan: 2022-03-10Bu yazılım geliştirme çağında, JavaScript hemen hemen her tür uygulamayı geliştirmek için kullanılabilir. Bununla birlikte, JavaScript'in dinamik olarak yazılması gerçeği, gevşek tip denetimi özelliği nedeniyle çoğu büyük kurumsal şirket için bir endişe kaynağı olabilir.
Neyse ki Ecma Teknik Komitesi 39'un JavaScript'e statik tipte bir sistem getirmesini beklemek zorunda değiliz. Bunun yerine TypeScript kullanabiliriz.
Dinamik olarak yazılan JavaScript, çalışma zamanında bu değişken somutlaştırılıncaya kadar bir değişkenin veri türünün farkında değildir. Büyük yazılım programları yazan geliştiriciler, daha önce bildirilen bir değişkeni, herhangi bir uyarı veya sorun olmaksızın farklı türde bir değere yeniden atama eğiliminde olabilir ve bu da genellikle hataların gözden kaçırılmasına neden olur.
Bu eğitimde, TypeScript'in ne olduğunu ve bir React projesinde onunla nasıl çalışılacağını öğreneceğiz. Sonunda, TypeScript ve mevcut React benzeri kancaları ( useState
, useEffect
, useReducer
, useContext
) kullanarak Money Heist adlı TV programı için bir bölüm seçici uygulamasından oluşan bir proje oluşturmuş olacağız. Bu bilgiyle, kendi projelerinizde TypeScript ile denemeler yapabilirsiniz.
Bu makale TypeScript'e bir giriş değildir. Bu nedenle, TypeScript ve JavaScript'in temel sözdiziminden geçmeyeceğiz. Ancak, takip etmek için bu dillerden herhangi birinde uzman olmanıza gerek yok, çünkü KISS ilkesini takip etmeye çalışacağız (basit tutun, aptalca).
TypeScript Nedir?
2019'da TypeScript, GitHub'da en çok kullanılan yedinci dil ve en hızlı büyüyen beşinci dil oldu. Ama TypeScript tam olarak nedir?
Resmi belgelere göre, TypeScript, düz JavaScript'i derleyen, JavaScript'in yazılı bir üst kümesidir. Microsoft ve açık kaynak topluluğu tarafından geliştirilir ve korunur.
Bu bağlamda "Süper küme", dilin JavaScript'in tüm özelliklerini ve işlevlerini ve ardından bazılarını içerdiği anlamına gelir. TypeScript, yazılı bir betik dilidir.
Geliştiricilere, tür açıklamaları, sınıfları ve arabirimi aracılığıyla kod tabanları üzerinde daha fazla kontrol sağlayarak geliştiricileri konsoldaki can sıkıcı hataları manuel olarak düzeltmek zorunda kalmaktan kurtarır.
TypeScript, JavaScript'i değiştirmek için oluşturulmadı. Bunun yerine, değerli yeni özelliklerle JavaScript'i genişletir. Düz JavaScript ile yazılmış tüm programlar, platformlar arası mobil uygulamalar ve Node.js'deki arka uçlar da dahil olmak üzere TypeScript'te beklendiği gibi çalışır.
Bu, bu eğitimde yapacağımız gibi TypeScript'te React uygulamalarını da yazabileceğiniz anlamına gelir.
Neden TypeScript?
Belki de TypeScript'in iyiliğini benimsemeye ikna olmadınız. Avantajlarından birkaçını ele alalım.
Daha Az Hata
Kodumuzdaki tüm hataları ortadan kaldıramayız, ancak onları azaltabiliriz. TypeScript, derleme zamanında türleri kontrol eder ve değişken türü değişirse hatalar atar.
Bu bariz ancak sık görülen hataları bu kadar erken bulabilmek, kodunuzu türlerle yönetmeyi çok daha kolay hale getirir.
Yeniden Düzenleme Daha Kolay
Muhtemelen çoğu zaman birçok şeyi yeniden düzenlemek istersiniz, ancak çok fazla başka koda ve diğer birçok dosyaya dokundukları için onları değiştirmekten çekinirsiniz.
TypeScript'te, bu tür şeyler, entegre geliştirme ortamınızdaki (IDE) "Sembolü yeniden adlandır" komutunun yalnızca bir tıklamasıyla genellikle yeniden düzenlenebilir.
JavaScript gibi dinamik olarak yazılan bir dilde, aynı anda birden çok dosyayı yeniden düzenlemenin tek yolu, normal ifadeler (RegExp) kullanan geleneksel "ara ve değiştir" işlevidir.
TypeScript gibi statik olarak yazılmış bir dilde artık "ara ve değiştir" gerekli değildir. “Tüm oluşumları bul” ve “Sembolü yeniden adlandır” gibi IDE komutlarıyla, bir nesne arabiriminin verilen işlevin, sınıfın veya özelliğinin uygulamasındaki tüm oluşumları görebilirsiniz.
TypeScript, yeniden düzenlenmiş bitin tüm örneklerini bulmanıza, onu yeniden adlandırmanıza ve yeniden düzenlemeden sonra kodunuzda herhangi bir tür uyuşmazlığı olması durumunda sizi bir derleme hatasıyla uyarmanıza yardımcı olur.
TypeScript, burada ele aldıklarımızdan bile daha fazla avantaja sahiptir.
TypeScript'in Dezavantajları
TypeScript, yukarıda vurgulanan umut verici özellikler göz önüne alındığında bile, kesinlikle dezavantajlarından yoksun değildir.
Yanlış Bir Güvenlik Anlayışı
TypeScript'in tür denetimi özelliği, geliştiriciler arasında genellikle yanlış bir güvenlik duygusu yaratır. Tip kontrolü gerçekten de kodumuzda bir sorun olduğunda bizi uyarır. Ancak, statik türler genel hata yoğunluğunu azaltmaz.
Bu nedenle, türler geliştirici tarafından yazıldığından ve çalışma zamanında kontrol edilmediğinden, programınızın gücü TypeScript kullanımınıza bağlı olacaktır.
Hatalarınızı azaltmak için TypeScript arıyorsanız, lütfen bunun yerine test odaklı geliştirmeyi düşünün.
Karmaşık Yazma Sistemi
Yazma sistemi birçok açıdan harika bir araç olsa da bazen biraz karmaşık olabilir. Bu dezavantaj, JavaScript ile tamamen birlikte çalışabilir olmasından kaynaklanmaktadır ve bu da karmaşıklık için daha fazla alan bırakmaktadır.
Ancak TypeScript hala JavaScript'tir, bu nedenle JavaScript'i anlamak önemlidir.
TypeScript Ne Zaman Kullanılır?
Aşağıdaki durumlarda TypeScript kullanmanızı tavsiye ederim:
- Uzun bir süre boyunca bakımı yapılacak bir uygulama oluşturmak istiyorsanız, TypeScript ile başlamanızı şiddetle tavsiye ederim, çünkü bu kendi kendini belgeleyen kodu destekler, böylece diğer geliştiricilerin kod tabanınıza katıldıklarında kodunuzu kolayca anlamalarına yardımcı olur. .
- Bir kitaplık oluşturmanız gerekiyorsa, onu TypeScript'te yazmayı düşünün. Kitaplığınızı kullanan geliştiricilere uygun türleri önermek için kod düzenleyicilerine yardımcı olacaktır.
Son birkaç bölümde TypeScript'in artılarını ve eksilerini dengeledik. Şimdi günün işine geçelim: Modern bir React projesinde TypeScript kurulumu .
Başlarken
Bir React Projesinde TypeScript kurmanın birkaç yolu vardır. Bu eğitimde, sadece ikisini ele alacağız.
Yöntem 1: React Uygulaması + TypeScript Oluştur
Yaklaşık iki yıl önce, React ekibi TypeScript desteğiyle Create React App 2.1'i yayınladı. Bu nedenle, TypeScript'i projenize dahil etmek için hiçbir zaman ağır işler yapmanız gerekmeyebilir.
Yeni bir React Uygulaması Oluştur projesi başlatmak için bunu çalıştırabilirsiniz…
npx create-react-app my-app --folder-name
… veya bu:
yarn create react-app my-app --folder-name
TypeScript'i Create React App projesine eklemek için önce onu ve ilgili @types
:
npm install --save typescript @types/node @types/react @types/react-dom @types/jest
… veya:
yarn add typescript @types/node @types/react @types/react-dom @types/jest
Ardından dosyaları yeniden adlandırın (örneğin, index.js
için index.tsx
) ve geliştirme sunucunuzu yeniden başlatın !
Bu hızlıydı, değil mi?
Yöntem 2: TypeScript'i Web Paketiyle Kurma
Webpack, JavaScript uygulamaları için statik bir modül paketleyicidir. Uygulamanızdan tüm kodu alır ve bir web tarayıcısında kullanılabilir hale getirir. Modüller, web sitenizde kolayca kullanılmak üzere paketlenmiş, uygulamanızın JavaScript, node_modules
, resimler ve CSS stillerinden oluşturulmuş yeniden kullanılabilir kod parçalarıdır.
Yeni Proje Oluştur
Projemiz için yeni bir dizin oluşturarak başlayalım:
mkdir react-webpack cd react-webpack
Projemizi başlatmak için npm kullanacağız:
npm init -y
Yukarıdaki komut, bazı varsayılan değerlere sahip bir package.json
dosyası oluşturacaktır. Ayrıca web paketi, TypeScript ve bazı React'e özgü modüller için bazı bağımlılıklar ekleyelim.
Paketleri Yükleme
Son olarak, gerekli paketleri kurmamız gerekecek. Komut satırı arabiriminizi (CLI) açın ve şunu çalıştırın:
#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
Ayrıca react-webpack
klasörümüzün altına manuel olarak birkaç farklı dosya ve klasör ekleyelim:
- Web paketiyle ilgili yapılandırmaları eklemek için
webpack.config.js
ekleyin. - Tüm TypeScript yapılandırmalarımız için
tsconfig.json
ekleyin. - Yeni bir dizin ekleyin,
src
. -
src
klasöründe yeni bir dizin oluşturun,components
. - Son olarak,
components
klasörüneindex.html
,App.tsx
veindex.tsx
ekleyin.
Proje Yapısı
Böylece klasör yapımız şöyle görünecek:
├── package.json ├── package-lock.json ├── tsconfig.json ├── webpack.config.js ├── .gitignore └── src └──components ├── App.tsx ├── index.tsx ├── index.html
Bazı Kodları Eklemeye Başlayın
index.html
ile başlayacağız:
<!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>
Bu, output
kimliğine sahip boş bir div
ile HTML'yi oluşturacaktır.
Kodu React bileşenimiz 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> );
Bir arayüz nesnesi yarattık ve buna HelloWorldProps
adını verdik, userName
ve lang
bir string
tipine sahip.
props
öğelerini App
bileşenimize aktardık ve dışa aktardık.
Şimdi index.tsx
içindeki kodu güncelleyelim:
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") );
App
bileşenini index.tsx
. Web paketi, .ts
veya .tsx
uzantılı herhangi bir dosya gördüğünde, bu dosyayı harika-typescript-loader kitaplığını kullanarak aktaracaktır.
TypeScript Yapılandırması
Ardından tsconfig.json
bazı yapılandırmalar ekleyeceğiz:
{ "compilerOptions": { "jsx": "react", "module": "commonjs", "noImplicitAny": true, "outDir": "./build/", "preserveConstEnums": true, "removeComments": true, "sourceMap": true, "target": "es5" }, "include": [ "src/components/index.tsx" ] }
Ayrıca tsconfig.json
eklediğimiz farklı seçeneklere de bakalım:
-
compilerOptions
Farklı derleyici seçeneklerini temsil eder. -
jsx:react
.tsx
dosyalarına JSX desteği ekler. -
lib
Derlemeye kitaplık dosyalarının bir listesini ekler (örneğin,es2015
kullanmak ECMAScript 6 sözdizimini kullanmamıza izin verir). -
module
Modül kodu üretir. -
noImplicitAny
any
tür ima edilen bildirimler için hataları artırır. -
outDir
Çıkış dizinini temsil eder. -
sourceMap
Uygulamada hata ayıklamak için çok yararlı olabilecek bir.map
dosyası oluşturur. -
target
Kodumuzun aktarılacağı hedef ECMAScript sürümünü temsil eder (belirli tarayıcı gereksinimlerimize göre bir sürüm ekleyebiliriz). -
include
Eklenecek dosya listesini belirtmek için kullanılır.
Web Paketi Yapılandırması
webpack.config.js
dosyasına biraz web paketi yapılandırması ekleyelim.
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", }), ], };
webpack.config.js
eklediğimiz farklı seçeneklere bakalım:
-
entry
Bu, uygulamamız için giriş noktasını belirtir. Derlememize dahil etmek istediğimiz tek bir dosya veya bir dizi dosya olabilir. -
output
Bu, çıktı yapılandırmasını içerir. Uygulama, projemizden diske paketlenmiş kod çıktısı almaya çalışırken buna bakar. Yol, çıktısı alınacak kodun çıktı dizinini temsil eder ve dosya adı, aynısı için dosya adını temsil eder. Genelliklebundle.js
olarak adlandırılır. -
resolve
Webpack, dosyayı gruplamak veya atlamak arasında karar vermek için bu özniteliğe bakar. Bu nedenle, projemizde web paketi, demetleme için.js
,.jsx
,.json
,.ts
ve.tsx
uzantılı dosyaları dikkate alacaktır. -
module
Web paketinin, uygulama tarafından istendiğinde, yükleyicileri kullanarak belirli bir dosyayı yüklemesini sağlayabiliriz. Aşağıdakileri belirten bir kural nesnesi alır:-
.tsx
veya.ts
uzantısıyla biten herhangi bir dosya, yüklenmek içinawesome-typescript-loader
kullanmalıdır; -
.js
uzantısıyla biten dosyalarsource-map-loader
ile yüklenmelidir; -
.css
uzantısıyla biten dosyalarcss-loader
ile yüklenmelidir.
-
-
plugins
Web paketinin kendi sınırlamaları vardır ve bunların üstesinden gelmek ve yeteneklerini genişletmek için eklentiler sağlar. Örneğin,html-webpack-plugin
,./src/component/index.html
dizinindekiindex.html
dosyasından tarayıcıya işlenen bir şablon dosyası oluşturur.
MiniCssExtractPlugin
, uygulamanın üst CSS
dosyasını işler.
package.json'a Script Ekleme
package.json
dosyamıza React uygulamaları oluşturmak için farklı komut dosyaları ekleyebiliriz:
"scripts": { "start": "webpack-dev-server --open", "build": "webpack" },
Şimdi, npm start
. Her şey yolunda gittiyse, şunu görmelisiniz:
Web paketi konusunda bilginiz varsa, bu kurulum için depoyu klonlayın ve projelerinizde kullanın.
Dosya Oluşturma
Bir src
klasörü ve bir index.tsx
dosyası oluşturun. Bu, React'i oluşturan temel dosya olacaktır.
Şimdi, npm start
, sunucumuzu çalıştıracak ve yeni bir sekme açacaktır. npm run build
, üretim için web paketi oluşturacak ve bizim için bir derleme klasörü oluşturacaktır.
Create React App ve web paketi yapılandırma yöntemini kullanarak TypeScript'i sıfırdan nasıl kuracağımızı gördük.
TypeScript'i tam olarak kavramanın en hızlı yollarından biri, mevcut Vanilla React projelerinizden birini TypeScript'e dönüştürmektir. Ne yazık ki, TypeScript'i mevcut bir Vanilla React projesinde aşamalı olarak benimsemek streslidir, çünkü tüm dosyaları çıkarmayı veya yeniden adlandırmayı gerektirir, bu da proje büyük bir ekibe aitse çakışmalara ve devasa bir çekme talebine neden olur.
Ardından, bir React projesinin TypeScript'e nasıl kolayca taşınacağına bakacağız.
Mevcut Bir Create React Uygulamasını TypeScript'e Taşıyın
Bu süreci daha yönetilebilir hale getirmek için, bireysel parçalar halinde geçiş yapmamızı sağlayacak adımlara böleceğiz. Projemizi taşımak için atacağımız adımlar şunlardır:
- TypeScript ve türleri ekleyin.
-
tsconfig.json
ekleyin. - Küçük başla.
- Dosya uzantısını
.tsx
olarak yeniden adlandırın.
1. TypeScript'i Projeye Ekleyin
Öncelikle projemize TypeScript eklememiz gerekecek. React projenizin Create React App ile başlatıldığını varsayarsak, aşağıdakileri çalıştırabiliriz:
# 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
Henüz hiçbir şeyi TypeScript olarak değiştirmediğimize dikkat edin. Projeyi yerel olarak başlatmak için komutu çalıştırırsak ( npm start
veya thread yarn start
), hiçbir şey değişmez. Eğer durum buysa, o zaman harika! Bir sonraki adım için hazırız.
2. tsconfig.json
Dosyasını ekleyin
TypeScript'ten yararlanmadan önce, onu tsconfig.json
dosyası aracılığıyla yapılandırmamız gerekiyor. Başlamanın en basit yolu, bu komutu kullanarak bir iskele kurmaktır:
npx tsc --init
Bu bize birçok yorumlanmış kodla birlikte bazı temel bilgileri verir. Şimdi, tsconfig.json
tüm kodu şununla değiştirin:
{ "compilerOptions": { "jsx": "react", "module": "commonjs", "noImplicitAny": true, "outDir": "./build/", "preserveConstEnums": true, "removeComments": true, "sourceMap": true, "target": "es5" }, "include": [ "./src/**/**/\*" ] }
TypeScript Yapılandırması
Ayrıca tsconfig.json
eklediğimiz farklı seçeneklere de bakalım:
-
compilerOptions
Farklı derleyici seçeneklerini temsil eder.-
target
Daha yeni JavaScript yapılarını ECMAScript 5 gibi daha eski bir sürüme çevirir. -
lib
Derlemeye kitaplık dosyalarının bir listesini ekler (örneğin, es2015 kullanmak ECMAScript 6 sözdizimini kullanmamıza izin verir). -
jsx:react
.tsx
dosyalarına JSX desteği ekler. -
lib
Derlemeye kitaplık dosyalarının bir listesini ekler (örneğin, es2015 kullanmak ECMAScript 6 sözdizimini kullanmamıza izin verir). -
module
Modül kodu üretir. -
noImplicitAny
any
tür ima edilen bildirimler için hata oluşturmak için kullanılır. -
outDir
Çıkış dizinini temsil eder. -
sourceMap
Uygulamamızda hata ayıklamak için çok yararlı olabilecek bir.map
dosyası oluşturur. -
include
Eklenecek dosya listesini belirtmek için kullanılır.
-
Konfigürasyon seçenekleri, bir projenin talebine göre değişiklik gösterecektir. Projenize neyin uyacağını bulmak için TypeScript seçenekleri elektronik tablosunu kontrol etmeniz gerekebilir.
Sadece işleri hazır hale getirmek için gerekli önlemleri aldık. Sonraki adımımız bir dosyayı TypeScript'e geçirmek.
3. Basit Bir Bileşenle Başlayın
TypeScript'in kademeli olarak benimsenme yeteneğinden yararlanın. Kendi hızınızda bir seferde bir dosya gidin. Kendiniz ve ekibiniz için mantıklı olanı yapın. Hepsini bir anda halletmeye çalışmayın.
Bunu düzgün bir şekilde dönüştürmek için iki şey yapmamız gerekiyor:
- Dosya uzantısını
.tsx
olarak değiştirin. - Tür ek açıklamasını ekleyin (bu, biraz TypeScript bilgisi gerektirir).
4. Dosya Uzantılarını .tsx
olarak yeniden adlandırın
Geniş bir kod tabanında, dosyaları tek tek yeniden adlandırmak yorucu görünebilir.
macOS'ta birden çok dosyayı yeniden adlandırın
Birden çok dosyayı yeniden adlandırmak zaman kaybı olabilir. Mac'te nasıl yapabileceğiniz aşağıda açıklanmıştır. Yeniden adlandırmak istediğiniz dosyaları içeren klasöre sağ tıklayın (veya Ctrl
+ tıklayın veya bir MacBook kullanıyorsanız izleme dörtgeninde iki parmağınızla aynı anda tıklayın). Ardından, “Finder'da Göster” seçeneğini tıklayın. Finder'da yeniden adlandırmak istediğiniz tüm dosyaları seçin. Seçili dosyalara sağ tıklayın ve “X öğelerini yeniden adlandır…” seçeneğini seçin. Ardından, şöyle bir şey göreceksiniz:
Bulmak istediğiniz dizeyi ve bulunan dizeyi değiştirmek istediğiniz dizeyi girin ve "Yeniden Adlandır" düğmesine basın. Tamamlandı.
Windows'ta birden çok dosyayı yeniden adlandırın
Windows'ta birden çok dosyayı yeniden adlandırmak bu öğreticinin kapsamı dışındadır, ancak eksiksiz bir kılavuz mevcuttur. Dosyaları yeniden adlandırdıktan sonra genellikle hata alırsınız; tür açıklamalarını eklemeniz yeterlidir. Bunu belgelerde tazeleyebilirsiniz.
Bir React uygulamasında TypeScript'in nasıl kurulacağını ele aldık. Şimdi, TypeScript kullanarak Money Heist için bir bölüm seçici uygulaması oluşturalım.
Temel TypeScript türlerini ele almayacağız. Bu öğreticiye devam etmeden önce belgeleri gözden geçirmek gerekir.
İnşa Zamanı
Bu süreci daha az yıldırıcı hissettirmek için, uygulamayı ayrı parçalar halinde oluşturmamızı sağlayacak adımlara böleceğiz. Money Heist bölüm seçicisini oluşturmak için atacağımız adımların tümü:
- Bir Create React Uygulaması Oluşturun.
- Bölümleri getir.
- interface.ts içinde bölümlerimiz için uygun türleri ve
interface.ts
oluşturun. -
store.tsx
bölümleri almak için mağazayı ayarlayın. -
action.ts
bölümleri almak için eylemi oluşturun. - Alınan bölümleri tutan bir
EpisodeList.tsx
bileşeni oluşturun. -
React Lazy and Suspense
kullanarakEpisodesList
bileşenini ana sayfamıza aktarın.
- interface.ts içinde bölümlerimiz için uygun türleri ve
- Bölüm ekleyin.
-
store.tsx
bölümleri eklemek için mağazayı ayarlayın. -
action.ts
bölüm eklemek için eylemi oluşturun.
-
- Bölümleri kaldırın.
-
store.tsx
bölümleri silmek için mağazayı ayarlayın. -
action.ts
bölümleri silmek için eylemi oluşturun.
-
- Favori bölüm.
- Favori bölümdeki
EpisodesList
bileşenini içe aktarın. - Favori bölümün içindeki
EpisodesList
Oluşturun.
- Favori bölümdeki
- Navigasyon için Reach Router'ı kullanma.
React'i Ayarla
React'i kurmanın en kolay yolu Create React App kullanmaktır. Create React App, tek sayfalık React uygulamaları oluşturmanın resmi olarak desteklenen bir yoludur. Konfigürasyon gerektirmeyen modern bir yapı kurulumu sunar.
Oluşturacağımız uygulamayı önyüklemek için kullanacağız. CLI'nizden aşağıdaki komutu çalıştırın:
npx create-react-app react-ts-app && cd react-ts-app
Kurulum başarılı olduktan sonra, npm start
çalıştırarak React sunucusunu başlatın.
TypeScript'te Arayüzleri ve Türleri Anlama
TypeScript'teki arabirimler, nesne özelliklerine tür vermemiz gerektiğinde kullanılır. Bu nedenle, türlerimizi tanımlamak için arayüzler kullanıyor olacağız.
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 }
Yukarıdaki kodu derlerken şu hatayı görürüz: “Mülkiyet salary
türleri uyumsuz. Tür string
, number
yazmak için atanamaz."
TypeScript'te bu tür hatalar, bir özelliğe veya değişkene tanımlanan türden başka bir tür atandığında meydana gelir. Spesifik olarak, yukarıdaki pasaj, salary
özelliğine number
türü yerine bir string
türü atandığı anlamına gelir.
src
klasörümüzde interface.ts
dosyasını oluşturalım. Bu kodu kopyalayıp içine yapıştırın:
/** |-------------------------------------------------- | 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> }
Arayüz adına bir “I” eklemek iyi bir uygulamadır. Kodu okunabilir hale getirir. Ancak, hariç tutmaya karar verebilirsiniz.
Bölüm Arayüzü
API'miz, airdate
, airstamp
, airtime
, id
, image
, name
, number
, runtime
, season
, summary
ve url
gibi bir dizi özellik döndürür. Bu nedenle, bir IEpisode
arabirimi tanımladık ve uygun veri türlerini nesne özelliklerine ayarladık.
IState Arayüzü
IState
arayüzümüz, sırasıyla episodes
ve favorites
kullanılanlar özelliklerine ve bir Array<IEpisode>
arayüzüne sahiptir.
IAeylem
IAction
arabirimi özellikleri, payload
ve type
. type
özelliği bir dize türüne sahipken, yükün bir Array | any
Array | any
.
Array | any
Array | any
, bölüm arabiriminin bir dizisi veya herhangi bir tür anlamına gelir.
Dispatch
türü, React.Dispatch
ve bir <IAction>
arabirimi olarak ayarlanmıştır. @types/react
kod tabanına göre React.Dispatch
dispatch
işlevi için standart tür olduğunu, <IAction>
ise Arayüz eyleminin bir dizisi olduğunu unutmayın.
Ayrıca, Visual Studio Code'da TypeScript denetleyicisi bulunur. Bu nedenle, yalnızca kodu vurgulayarak veya üzerine gelerek uygun türü önermek için yeterince akıllıdır.
Başka bir deyişle, uygulamalarımız genelinde arayüzümüzü kullanabilmemiz için onu dışa aktarmamız gerekiyor. Şimdiye kadar, nesnemizin türünü tutan mağazamız ve arayüzlerimiz var. Şimdi mağazamızı oluşturalım. Diğer arabirimlerin açıklananlarla aynı kuralları izlediğine dikkat edin.
Bölümleri Getir
Mağaza Oluşturma
Bölümlerimizi getirmek için, verilerin ilk durumunu tutan ve redüktör işlevimizi tanımlayan bir depoya ihtiyacımız var.
Bunu ayarlamak için useReducer
kancasını kullanacağız. src
klasörünüzde bir store.tsx
dosyası oluşturun. Aşağıdaki kodu kopyalayıp içine yapıştırın.
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} }
Mağazayı oluşturmak için attığımız adımlar şunlardır:
- Mağazamızı tanımlarken,
useReducer
kancasına vecreateContext
API'sine ihtiyacımız var, bu yüzden onu içe aktardık. -
IState
veIAction
./types/interfaces
. - IState türünde bir
initialState
nesnesi ve her ikisi de sırasıyla boş bir diziye ayarlanmış bölümlerin ve sık kullanılanların özellikleriniIState
. - Ardından,
createContext
yöntemini tutan veinitialState
geçirilen birStore
değişkeni oluşturduk.
createContext
yöntem türü <IState | any>
<IState | any>
, bu, bir tür <IState>
veya any
biri olabileceği anlamına gelir. Bu makalede sıklıkla kullanılan any
türü göreceğiz.
- Ardından, bir
reducer
işlevi bildirdik vestate
veaction
parametre olarak ilettik.reducer
işlevi,action.type
değerini kontrol eden bir switch ifadesine sahiptir. DeğerFETCH_DATA
ise, durumumuzun(...state)
ve eylem yükümüzü tutan bölüm durumunun bir kopyasına sahip bir nesne döndürür. - switch ifadesinde bir
default
durumu döndürürüz.
Redüktör işlevindeki state
ve action
parametrelerinin sırasıyla IState
ve IAction
türleri olduğunu unutmayın. Ayrıca, reducer
işlevi bir tür IState
.
- Son olarak, bir
StoreProvider
işlevi bildirdik. Bu, uygulamamızdaki tüm bileşenlerin mağazaya erişmesini sağlayacaktır. - Bu işlev
children
bir destek olarak alır veStorePrivder
işlevinin içindeuseReducer
kancasını bildirdik. -
state
vedispatch
. - Mağazamızı tüm bileşenler için erişilebilir kılmak için,
state
vedispatch
içeren bir nesne değeri ilettik.
Bölümlerimizi ve favori state
içeren durum, diğer bileşenler tarafından erişilebilir hale getirilirken, dispatch
durumu değiştiren bir işlevdir.
- Uygulamamızda kullanılabilmesi için
Store
veStoreProvider
dışa aktaracağız.
Action.ts oluştur
Kullanıcıya gösterilecek bölümleri almak için API'ye isteklerde bulunmamız gerekecek. Bu bir eylem dosyasında yapılacaktır. Bir Action.ts
dosyası oluşturun ve ardından aşağıdaki kodu yapıştırın:
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 }) }
Öncelikle, bu dosyada kullanılabilmesi için arayüzlerimizi içe aktarmamız gerekiyor. Eylemi oluşturmak için aşağıdaki adımlar atılmıştır:
-
fetchDataAction
işlevi, bir parametre olarakdispatch
malzemeleri alır. - İşlevimiz eşzamansız olduğundan,
async
veawait
olacağız. - API uç noktamızı tutan bir değişken (
URL
) oluşturuyoruz. - API'den gelen yanıtı tutan
data
adında başka bir değişkenimiz var. - Daha sonra,
data.json()
çağırarak JSON formatında cevabı aldıktan sonra, JSON cevabınıdataJSON
içinde saklarız. - Son olarak,
type
özelliğine veFETCH_DATA
dizesine sahip bir gönderme işlevi döndürürüz. Ayrıca birpayload()
vardır._embedded.episodes
,endpoint
noktamızdaki bölümler nesnesinin dizisidir.
fetchDataAction
işlevinin uç noktamızı aldığını, onu JSON
nesnelerine dönüştürdüğünü ve Store'da daha önce bildirilen durumu güncelleyen gönderme işlevini döndürdüğünü unutmayın.
Dışa aktarılan gönderim türü React.Dispatch
olarak ayarlanmıştır. React.Dispatch
@types/react
kod tabanına göre gönderme işlevi için standart tür olduğunu, <IAction>
ise Arayüz Eyleminin bir dizisi olduğunu unutmayın.
Bölüm Listesi Bileşeni
Uygulamamızın yeniden kullanılabilirliğini korumak için, alınan tüm bölümleri ayrı bir dosyada tutacağız ve ardından dosyayı ana sayfa bileşenimize homePage
.
components
klasöründe bir EpisodesList.tsx
dosyası oluşturun ve aşağıdaki kodu kopyalayıp ona yapıştırın:
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
-
IEpisode
veIProps
interfaces.tsx
dosyasından içe aktarıyoruz. - Ardından, sahne alan bir
EpisodesList
işlevi oluşturuyoruz. Props, bir türIProps
sahipken, işlevin birArray<JSX.Element>
türü vardır.
Visual Studio Code, işlev JSX.Element[]
olarak yazılmasını önerir.
Array<JSX.Element>
, JSX.Element[]
eşit olsa da, Array<JSX.Element>
genel kimlik olarak adlandırılır. Bu nedenle, genel kalıp bu makalede sıklıkla kullanılacaktır.
- İşlevin içinde, tür olarak
IEpisode
sahip olanprops
öğesindenepisodes
yok ederiz.
Genel kimlik hakkında bilgi edinin, Devam ederken bu bilgiye ihtiyaç duyulacaktır.
- Birkaç HTML etiketi döndürmek için
episodes
aksesuarlarını döndürdük ve bunların haritasını çıkardık. - İlk bölüm,
episode.id
olankey
ve daha sonra oluşturulacak olan partitionepisode-box
className
içerir. Bölümlerimizin görüntüleri olduğunu biliyoruz; bu nedenle, resim etiketi. - Görüntünün, bir
episode.image
veya birepisode.image.medium
olup olmadığını kontrol eden bir üçlü operatörü vardır. Aksi takdirde, resim bulunamazsa boş bir dize görüntüleriz. Ayrıca, bölüm adını birepisode.name
ekledik.
section
, bir bölümün ait olduğu sezonu ve numarasını gösteriyoruz. Fav
metnine sahip bir düğmemiz var. Uygulamamızda kullanabilmemiz için EpisodesList
bileşenini dışa aktardık.
Ana Sayfa Bileşeni
Ana sayfanın API çağrısını tetiklemesini ve oluşturduğumuz EpisodesList
bileşenini kullanarak bölümleri görüntülemesini istiyoruz. components
klasörünün içinde HomePage
bileşenini oluşturun ve aşağıdaki kodu kopyalayıp ona yapıştırın:
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
-
useContext
,useEffect
,lazy
veSuspense
öğelerini içe aktarıyoruz. İçe aktarılan uygulama bileşeni, diğer tüm bileşenlerin mağazanın değerini alması gereken temeldir. - Ayrıca
Store
,IEpisodeProps
veFetchDataAction
ilgili dosyalarından içe aktarırız. - React 16.6'da bulunan
React.lazy
özelliğini kullanarakEpisodesList
bileşenini içe aktarıyoruz.
React tembel yükleme, kod bölme kuralını destekler. Böylece, EpisodesList
bileşenimiz bir kerede yüklenmek yerine dinamik olarak yüklenir, böylece uygulamamızın performansı iyileştirilir.
- Durumu
state
veStore
sahne olarakdispatch
. -
useEffect
kancasındaki ve işareti (&&), bölüm durumumuzunempty
(veya 0'a eşit) olup olmadığını kontrol eder. Aksi takdirde,fetchDataAction
işlevini döndürürüz. - Son olarak,
App
bileşenini iade ediyoruz. İçinde,Suspense
sarmalayıcısını kullanıyoruz veloading
metniyle birlikte bir div'efallback
ayarlıyoruz. API'den yanıt beklerken bu kullanıcıya gösterilecektir. -
EpisodesList
bileşeni, veriler mevcut olduğunda eklenecektir veepisodes
içerecek olan veriler, ona yaydığımız şeydir.
Index.txs Kurulumu
Ana Homepage
bileşeninin StoreProvider
alt öğesi olması gerekir. Bunu index
dosyasında yapmamız gerekecek. index.js
index.tsx
olarak yeniden adlandırın ve aşağıdaki kodu yapıştırın:
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') )
StoreProvider
, HomePage
ve index.css
dosyalarını ilgili dosyalarından içe aktarıyoruz. 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.
Uzun yoldan geldik. 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.
EpisodeList.tsx
biraz daha snippet ekleyeceğiz. Vurgulanan kodu kopyalayıp yapıştırın:
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
Sahne olarak togglefavaction
, favorites
ve store
dahil ediyoruz ve mağazadan bir dispatch
olan state
'i yok ediyoruz. Favori bölümümüzü seçmek için toggleFavAction
yöntemini bir onClick
olayına dahil ediyoruz ve state
, dispatch
ve episode
özelliklerini işleve argüman olarak iletiyoruz.
Son olarak, fav.id
(favori kimlik) episode.id
ile eşleşip eşleşmediğini kontrol etmek için favorite
durum arasında dolaşıyoruz. Varsa, Unfav
ve Fav
metni arasında geçiş yaparız. Bu, kullanıcının o bölümü favorilerine alıp almadığını bilmesine yardımcı olur.
Sona yaklaşıyoruz. Ancak yine de, kullanıcı ana sayfadaki bölümler arasından seçim yaptığında favori bölümlerin bağlanabileceği bir sayfaya ihtiyacımız var.
Buraya kadar geldiyseniz, sırtınızı sıvazlayın.
Favori Sayfası Bileşeni
components
klasöründe bir FavPage.tsx
dosyası oluşturun. Aşağıdaki kodu kopyalayıp ona yapıştırın:
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> ) }
Favori bölümleri seçmenin ardındaki mantığı oluşturmak için küçük bir kod yazdık. lazy
ve Suspense
içe aktarıyoruz. Ayrıca Store
, IEpisodeProps
ve toggleFavAction
ilgili dosyalarından içe aktarırız.
React.lazy
özelliğini kullanarak EpisodesList
bileşenimizi içe aktarıyoruz. Son olarak, App
bileşenini iade ediyoruz. İçinde, Suspense
sarmalayıcısını kullanıyoruz ve yükleme metniyle bir div'e geri dönüş ayarlıyoruz.
Bu, Homepage
bileşenine benzer şekilde çalışır. Bu bileşen, kullanıcının favorilerine eklemiş olduğu bölümleri almak için mağazaya erişecektir. Ardından, bölümlerin listesi, EpisodesList
bileşenine geçirilir.
HomePage.tsx
dosyasına birkaç snippet daha ekleyelim.
../Actions
toggleFavAction
ekleyin. Ayrıca toggleFavAction
yöntemini sahne malzemesi olarak dahil edin.
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
bağlantılı olması gerekiyor, bu yüzden App.tsx
içindeki başlığımızda bir bağlantıya ihtiyacımız var. Bunu başarmak için React Router'a benzer bir kütüphane olan Reach Router'ı kullanıyoruz. William Le, Reach Router ve React Router arasındaki farkları açıklıyor.
npm install @reach/router @types/reach__router
. Hem Reach Router kitaplığını hem de access reach-router
türlerini kuruyoruz.
Başarılı kurulumdan sonra Link
@reach/router
içe aktarın.
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
useContext
yok ediyoruz. Son olarak, evimizin bir Link
ve /
için bir yolu olacak, favorimizin /faves
için bir yolu var.
{state.favourites.length}
, favori durumlarındaki bölüm sayısını kontrol eder ve görüntüler.
Son olarak index.tsx
dosyamızda sırasıyla FavPage
ve HomePage
bileşenlerini import edip Router
içerisine sarıyoruz.
Vurgulanan kodu mevcut koda kopyalayın:
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') )
Şimdi, uygulanan ADD_FAV
nasıl çalıştığını görelim.
Favori İşlevselliği Kaldır
Son olarak, “Bölüm kaldır özelliğini” ekleyeceğiz, böylece butona tıklandığında favori bölüm ekleme veya çıkarma arasında geçiş yapıyoruz. Başlıkta eklenen veya kaldırılan bölümlerin sayısını görüntüleyeceğiz.
MAĞAZA
"Favori bölümü kaldır" işlevini oluşturmak için mağazamıza başka bir vaka ekleyeceğiz. Bu nedenle Store.tsx
gidin ve vurgulanan kodu ekleyin:
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} }
REMOVE_FAV
adında başka bir durum daha ekleriz ve initialState
kopyasını içeren bir nesne döndürürüz. Ayrıca, favorites
durumu, eylem yükünü içerir.
EYLEM
Aşağıdaki vurgulanan kodu kopyalayın ve action.ts
yapıştırın:
{import
{ IAction, IEpisode, IState, Dispatch } from './types/interfaces'
içe aktarınexport 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) }
IState
arabirimini ./types/interfaces
öğesinden içe aktarıyoruz, çünkü onu tür olarak toggleFavAction
işlevinde state
desteğine aktarmamız gerekecek.
favorites
durumunda bulunan bir bölüm olup olmadığını kontrol etmek için bir episodeInFav
değişkeni oluşturulur.
Favori kimliğinin bölüm kimliğine eşit olup olmadığını kontrol etmek için favori durumunu filtreleriz. Böylece, dispatchObj
bir REMOVE_FAV
türü ve bir favWithoutEpisode
yükü yeniden atanır.
Uygulamamızın sonucunu önizleyelim.
Çözüm
Bu yazıda, bir React projesinde TypeScript'in nasıl kurulacağını ve bir projenin Vanilla React'ten TypeScript'e nasıl taşınacağını gördük.
Ayrıca TypeScript'in React projelerinde nasıl kullanıldığını görmek için TypeScript ve React ile bir uygulama geliştirdik. Birkaç şey öğrenebildiğine inanıyorum.
Lütfen geri bildirimlerinizi ve deneyimlerinizi TypeScript ile aşağıdaki yorumlar bölümünde paylaşın. Ne bulduğunu görmek isterim!
Bu makalenin destekleyici deposu GitHub'da mevcuttur.
Referanslar
- "Bir React Uygulamasını TypeScript'e Nasıl Geçiririm?" Joe Previte
- “React Uygulamanızda TypeScript Neden ve Nasıl Kullanılır?” Mahesh Haldar