Einrichten von TypeScript für moderne React-Projekte mit Webpack
Veröffentlicht: 2022-03-10In dieser Ära der Softwareentwicklung kann JavaScript verwendet werden, um fast jede Art von App zu entwickeln. Die Tatsache, dass JavaScript dynamisch typisiert ist, könnte jedoch für die meisten großen Unternehmen ein Problem darstellen, da es eine lockere Typprüfungsfunktion enthält.
Glücklicherweise müssen wir nicht warten, bis das Ecma Technical Committee 39 ein statisches Typsystem in JavaScript einführt. Wir können stattdessen TypeScript verwenden.
Da JavaScript dynamisch typisiert ist, ist der Datentyp einer Variablen erst bekannt, wenn diese Variable zur Laufzeit instanziiert wird. Entwickler, die große Softwareprogramme schreiben, neigen möglicherweise dazu, eine zuvor deklarierte Variable einem Wert eines anderen Typs zuzuweisen, ohne dass eine Warnung oder ein Problem auftritt, was zu häufig übersehenen Fehlern führt.
In diesem Tutorial lernen wir, was TypeScript ist und wie man damit in einem React-Projekt arbeitet. Am Ende haben wir ein Projekt erstellt, das aus einer App zur Episodenauswahl für die TV-Show Haus des Geldes besteht, die TypeScript und aktuelle React-ähnliche Hooks ( useState , useEffect , useReducer , useContext ) verwendet. Mit diesem Wissen können Sie in Ihren eigenen Projekten mit TypeScript experimentieren.
Dieser Artikel ist keine Einführung in TypeScript. Daher gehen wir nicht auf die grundlegende Syntax von TypeScript und JavaScript ein. Sie müssen jedoch kein Experte in einer dieser Sprachen sein, um mitzumachen, denn wir werden versuchen, dem KISS-Prinzip zu folgen (keep it simple, stupid).
Was ist TypeScript?
Im Jahr 2019 wurde TypeScript auf GitHub als die siebthäufigste Sprache und die am fünftschnellsten wachsende Sprache eingestuft. Aber was genau ist TypeScript?
Laut der offiziellen Dokumentation ist TypeScript eine typisierte Obermenge von JavaScript, die zu einfachem JavaScript kompiliert wird. Es wird von Microsoft und der Open-Source-Community entwickelt und gepflegt.
„Superset“ bedeutet in diesem Zusammenhang, dass die Sprache alle Merkmale und Funktionen von JavaScript enthält und noch einige mehr. TypeScript ist eine typisierte Skriptsprache.
Es bietet Entwicklern mehr Kontrolle über ihre Codebasis über seine Typannotation, Klassen und Schnittstelle und erspart Entwicklern die manuelle Behebung lästiger Fehler in der Konsole.
TypeScript wurde nicht erstellt, um JavaScript zu ändern. Stattdessen erweitert es JavaScript um wertvolle neue Funktionen. Jedes Programm, das in einfachem JavaScript geschrieben ist, wird auch wie erwartet in TypeScript ausgeführt, einschließlich plattformübergreifender mobiler Apps und Backends in Node.js.
Das bedeutet, dass Sie auch React-Apps in TypeScript schreiben können, wie wir es in diesem Tutorial tun werden.
Warum TypeScript?
Vielleicht sind Sie nicht davon überzeugt, die Vorteile von TypeScript anzunehmen. Betrachten wir einige seiner Vorteile.
Weniger Fehler
Wir können nicht alle Fehler in unserem Code beseitigen, aber wir können sie reduzieren. TypeScript prüft zur Kompilierzeit auf Typen und gibt Fehler aus, wenn sich der Variablentyp ändert.
In der Lage zu sein, diese offensichtlichen, aber häufigen Fehler so früh zu finden, macht es viel einfacher, Ihren Code mit Typen zu verwalten.
Umgestaltung ist einfacher
Sie möchten wahrscheinlich oft ziemlich viele Dinge umgestalten, aber weil sie so viel anderen Code und viele andere Dateien berühren, sind Sie vorsichtig, sie zu ändern.
In TypeScript können solche Dinge oft mit nur einem Klick auf den Befehl „Symbol umbenennen“ in Ihrer integrierten Entwicklungsumgebung (IDE) umgestaltet werden.

In einer dynamisch typisierten Sprache wie JavaScript ist die einzige Möglichkeit, mehrere Dateien gleichzeitig umzugestalten, die traditionelle „Suchen und Ersetzen“-Funktion mit regulären Ausdrücken (RegExp).
In einer statisch typisierten Sprache wie TypeScript ist „Suchen und Ersetzen“ nicht mehr erforderlich. Mit IDE-Befehlen wie „Alle Vorkommen finden“ und „Symbol umbenennen“ können Sie alle Vorkommen der angegebenen Funktion, Klasse oder Eigenschaft einer Objektschnittstelle in der App anzeigen.
TypeScript hilft Ihnen dabei, alle Instanzen des umgestalteten Bits zu finden, es umzubenennen und Sie mit einem Kompilierungsfehler zu warnen, falls Ihr Code nach der Umgestaltung irgendwelche Typenkonflikte aufweist.
TypeScript hat noch mehr Vorteile als das, was wir hier behandelt haben.
Nachteile von TypeScript
TypeScript ist sicherlich nicht ohne Nachteile, selbst angesichts der oben hervorgehobenen vielversprechenden Funktionen.
Ein falsches Sicherheitsgefühl
Die Type-Checking-Funktion von TypeScript erzeugt bei Entwicklern oft ein falsches Sicherheitsgefühl. Die Typprüfung warnt uns tatsächlich, wenn etwas mit unserem Code nicht stimmt. Statische Typen reduzieren jedoch nicht die Gesamtfehlerdichte.
Daher hängt die Stärke Ihres Programms von Ihrer Verwendung von TypeScript ab, da Typen vom Entwickler geschrieben und nicht zur Laufzeit überprüft werden.
Wenn Sie TypeScript verwenden möchten, um Ihre Fehler zu reduzieren, sollten Sie stattdessen die testgetriebene Entwicklung in Betracht ziehen.
Kompliziertes Schreibsystem
Das Tippsystem ist zwar in vielerlei Hinsicht ein großartiges Werkzeug, kann aber manchmal etwas kompliziert sein. Dieser Nachteil ergibt sich aus der vollständigen Interoperabilität mit JavaScript, was noch mehr Raum für Komplikationen lässt.
TypeScript ist jedoch immer noch JavaScript, daher ist es wichtig, JavaScript zu verstehen.
Wann verwendet man TypeScript?
Ich würde Ihnen in folgenden Fällen zur Verwendung von TypeScript raten:
- Wenn Sie eine Anwendung erstellen möchten, die über einen langen Zeitraum gewartet werden soll, würde ich dringend empfehlen, mit TypeScript zu beginnen, da es selbstdokumentierenden Code fördert und so anderen Entwicklern hilft, Ihren Code leicht zu verstehen, wenn sie Ihrer Codebasis beitreten .
- Wenn Sie eine Bibliothek erstellen müssen, sollten Sie sie in TypeScript schreiben. Es hilft Code-Editoren, Entwicklern, die Ihre Bibliothek verwenden, die geeigneten Typen vorzuschlagen.
In den letzten Abschnitten haben wir die Vor- und Nachteile von TypeScript abgewogen. Kommen wir zum Tagesgeschäft: TypeScript in einem modernen React-Projekt einrichten .
Einstieg
Es gibt mehrere Möglichkeiten, TypeScript in einem React-Projekt einzurichten. In diesem Tutorial behandeln wir nur zwei.
Methode 1: React-App + TypeScript erstellen
Vor etwa zwei Jahren veröffentlichte das React-Team die Create React App 2.1 mit TypeScript-Unterstützung. Sie müssen sich also möglicherweise nie die Mühe machen, TypeScript in Ihr Projekt zu integrieren.

Um ein neues Create React App-Projekt zu starten, können Sie Folgendes ausführen …
npx create-react-app my-app --folder-name… oder dieses:
yarn create react-app my-app --folder-name Um TypeScript zu einem Create React App-Projekt hinzuzufügen, installieren Sie es zuerst und die entsprechenden @types :
npm install --save typescript @types/node @types/react @types/react-dom @types/jest… oder:
yarn add typescript @types/node @types/react @types/react-dom @types/jest Benennen Sie als Nächstes die Dateien um (z. B. index.js in index.tsx ) und starten Sie Ihren Entwicklungsserver neu !
Das ging schnell, oder?
Methode 2: Richten Sie TypeScript mit Webpack ein
Webpack ist ein statischer Modul-Bundler für JavaScript-Anwendungen. Es nimmt den gesamten Code aus Ihrer Anwendung und macht ihn in einem Webbrowser nutzbar. Module sind wiederverwendbare Codeblöcke, die aus JavaScript, node_modules , Bildern und CSS-Stilen Ihrer App erstellt wurden und für die einfache Verwendung auf Ihrer Website gepackt sind.
Erstellen Sie ein neues Projekt
Beginnen wir damit, ein neues Verzeichnis für unser Projekt zu erstellen:
mkdir react-webpack cd react-webpackWir werden npm verwenden, um unser Projekt zu initialisieren:
npm init -y Der obige Befehl generiert eine package.json -Datei mit einigen Standardwerten. Lassen Sie uns auch einige Abhängigkeiten für Webpack, TypeScript und einige React-spezifische Module hinzufügen.
Pakete installieren
Zuletzt müssen wir die erforderlichen Pakete installieren. Öffnen Sie Ihre Befehlszeilenschnittstelle (CLI) und führen Sie Folgendes aus:
#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 Lassen Sie uns auch manuell einige verschiedene Dateien und Ordner unter unserem react-webpack Ordner hinzufügen:
- Fügen Sie
webpack.config.jshinzu, um Webpack-bezogene Konfigurationen hinzuzufügen. - Fügen Sie
tsconfig.jsonfür alle unsere TypeScript-Konfigurationen hinzu. - Fügen Sie ein neues Verzeichnis hinzu,
src. - Erstellen Sie ein neues Verzeichnis,
components, imsrcOrdner. - Fügen Sie schließlich
index.html,App.tsxundindex.tsximcomponentshinzu.
Projektstruktur
Somit sieht unsere Ordnerstruktur in etwa so aus:
├── package.json ├── package-lock.json ├── tsconfig.json ├── webpack.config.js ├── .gitignore └── src └──components ├── App.tsx ├── index.tsx ├── index.htmlBeginnen Sie mit dem Hinzufügen von Code
Wir beginnen mit 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> Dadurch wird der HTML-Code mit einem leeren div mit einer ID von output erstellt.
Fügen wir den Code unserer React-Komponente 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> ); Wir haben ein Schnittstellenobjekt erstellt und es HelloWorldProps genannt, wobei userName und lang vom Typ string sind.
Wir haben props an unsere App Komponente übergeben und exportiert.
Lassen Sie uns nun den Code in 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") ); Wir haben gerade die App -Komponente in index.tsx importiert. Wenn Webpack eine Datei mit der Erweiterung .ts oder .tsx sieht, transpiliert es diese Datei mithilfe der awesome-typescript-loader-Bibliothek.
TypeScript-Konfiguration
Anschließend fügen wir tsconfig.json eine Konfiguration hinzu:
{ "compilerOptions": { "jsx": "react", "module": "commonjs", "noImplicitAny": true, "outDir": "./build/", "preserveConstEnums": true, "removeComments": true, "sourceMap": true, "target": "es5" }, "include": [ "src/components/index.tsx" ] } Sehen wir uns auch die verschiedenen Optionen an, die wir zu tsconfig.json hinzugefügt haben:
-
compilerOptionsRepräsentiert die verschiedenen Compileroptionen. -
jsx:reactFügt Unterstützung für JSX in.tsxDateien hinzu. -
libFügt der Kompilierung eine Liste von Bibliotheksdateien hinzu (z. B. ermöglicht uns die Verwendung vones2015die Verwendung von ECMAScript 6-Syntax). -
moduleGeneriert Modulcode. -
noImplicitAnyFehler für Deklarationen mit einem impliziertenanyTyp aus. -
outDirRepräsentiert das Ausgabeverzeichnis. -
sourceMapErzeugt eine.map-Datei, die zum Debuggen der App sehr nützlich sein kann. -
targetStellt die ECMAScript-Zielversion dar, auf die unser Code heruntertranspiliert werden soll (wir können eine Version basierend auf unseren spezifischen Browseranforderungen hinzufügen). -
includeWird verwendet, um die einzuschließende Dateiliste anzugeben.
Webpack-Konfiguration
Lassen Sie uns einige Webpack-Konfigurationen zu 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", }), ], }; Schauen wir uns die verschiedenen Optionen an, die wir zu webpack.config.js hinzugefügt haben:
-
entryDies gibt den Einstiegspunkt für unsere App an. Es kann sich um eine einzelne Datei oder ein Array von Dateien handeln, die wir in unseren Build aufnehmen möchten. -
outputEnthält die Ausgangskonfiguration. Die App sieht sich dies an, wenn sie versucht, gebündelten Code aus unserem Projekt auf die Festplatte auszugeben. Der Pfad stellt das Ausgabeverzeichnis für den auszugebenden Code dar, und der Dateiname stellt den Dateinamen für dasselbe dar. Es heißt im Allgemeinenbundle.js. - Auflösen
resolveprüft dieses Attribut, um zu entscheiden, ob die Datei gebündelt oder übersprungen werden soll. Daher berücksichtigt webpack in unserem Projekt Dateien mit den Erweiterungen.js,.jsx,.json,.tsund.tsxfür das Bündeln. -
moduleWir können es Webpack ermöglichen, eine bestimmte Datei zu laden, wenn sie von der App angefordert wird, indem wir Loader verwenden. Es nimmt ein Regelobjekt an, das Folgendes angibt:- Jede Datei, die mit der Erweiterung
.tsxoder.tsendet, sollte zum Laden denawesome-typescript-loaderverwenden; - Dateien, die mit der Erweiterung
.js, sollten mitsource-map-loadergeladen werden; - Dateien, die mit der Erweiterung
.cssenden, sollten mitcss-loadergeladen werden.
- Jede Datei, die mit der Erweiterung
-
pluginsWebpack hat seine eigenen Einschränkungen und bietet Plugins, um diese zu überwinden und seine Fähigkeiten zu erweitern. Beispielsweise erstellthtml-webpack-plugineine Vorlagendatei, die für den Browser aus der Dateiindex.htmlim Verzeichnis./src/component/index.htmlwird.
MiniCssExtractPlugin rendert die übergeordnete CSS -Datei der App.
Hinzufügen von Skripts zu package.json
Wir können verschiedene Skripte hinzufügen, um React-Apps in unserer Datei package.json erstellen:
"scripts": { "start": "webpack-dev-server --open", "build": "webpack" }, Führen Sie nun npm start in Ihrer CLI aus. Wenn alles gut gelaufen ist, sollten Sie Folgendes sehen:

Wenn Sie ein Händchen für Webpacks haben, klonen Sie das Repository für dieses Setup und verwenden Sie es in Ihren Projekten.
Dateien erstellen
Erstellen Sie einen src -Ordner und eine index.tsx -Datei. Dies ist die Basisdatei, die React rendert.
Wenn wir jetzt npm start ausführen, wird unser Server ausgeführt und ein neuer Tab geöffnet. Wenn Sie npm run build wird das Webpack für die Produktion erstellt und ein Build-Ordner für uns erstellt.
Wir haben gesehen, wie man TypeScript mit der Create React App und der Webpack-Konfigurationsmethode von Grund auf neu einrichtet.
Eine der schnellsten Möglichkeiten, TypeScript vollständig zu verstehen, besteht darin, eines Ihrer vorhandenen Vanilla-React-Projekte in TypeScript zu konvertieren. Leider ist die schrittweise Übernahme von TypeScript in ein bestehendes Vanilla-React-Projekt stressig, da es dazu führt, dass alle Dateien ausgeworfen oder umbenannt werden müssen, was zu Konflikten und einem riesigen Pull-Request führen würde, wenn das Projekt zu einem großen Team gehört.
Als Nächstes sehen wir uns an, wie Sie ein React-Projekt einfach zu TypeScript migrieren können.
Migrieren Sie eine vorhandene Create React-App zu TypeScript
Um diesen Prozess überschaubarer zu machen, werden wir ihn in Schritte unterteilen, die es uns ermöglichen, in einzelnen Abschnitten zu migrieren. Hier sind die Schritte, die wir unternehmen werden, um unser Projekt zu migrieren:
- Fügen Sie TypeScript und Typen hinzu.
- Fügen Sie
tsconfig.json. - Fangen Sie klein an.
- Benennen Sie die Dateierweiterung in
.tsxum.
1. Fügen Sie TypeScript zum Projekt hinzu
Zuerst müssen wir TypeScript zu unserem Projekt hinzufügen. Angenommen, Ihr React-Projekt wurde mit Create React App gebootstrapped, können wir Folgendes ausführen:
# 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 Beachten Sie, dass wir noch nichts an TypeScript geändert haben. Wenn wir den Befehl ausführen, um das Projekt lokal zu starten ( npm start oder yarn start ), ändert sich nichts. Wenn dem so ist, dann super! Wir sind bereit für den nächsten Schritt.
2. Fügen Sie die Datei tsconfig.json
Bevor wir TypeScript nutzen können, müssen wir es über die Datei tsconfig.json konfigurieren. Der einfachste Weg, um anzufangen, besteht darin, mit diesem Befehl ein Gerüst zu erstellen:
npx tsc --init Dies verschafft uns einige Grundlagen mit viel kommentiertem Code. Ersetzen Sie nun den gesamten Code in tsconfig.json durch diesen:
{ "compilerOptions": { "jsx": "react", "module": "commonjs", "noImplicitAny": true, "outDir": "./build/", "preserveConstEnums": true, "removeComments": true, "sourceMap": true, "target": "es5" }, "include": [ "./src/**/**/\*" ] }TypeScript-Konfiguration
Sehen wir uns auch die verschiedenen Optionen an, die wir zu tsconfig.json hinzugefügt haben:
-
compilerOptionsRepräsentiert die verschiedenen Compileroptionen.-
targetÜbersetzt neuere JavaScript-Konstrukte in eine ältere Version wie ECMAScript 5. -
libFügt der Kompilierung eine Liste von Bibliotheksdateien hinzu (z. B. ermöglicht uns die Verwendung von es2015 die Verwendung von ECMAScript 6-Syntax). -
jsx:reactFügt Unterstützung für JSX in.tsxDateien hinzu. -
libFügt der Kompilierung eine Liste von Bibliotheksdateien hinzu (z. B. ermöglicht uns die Verwendung von es2015 die Verwendung von ECMAScript 6-Syntax). -
moduleGeneriert Modulcode. -
noImplicitAnyWird verwendet, um Fehler für Deklarationen mit einem implizitenanyTyp auszulösen. -
outDirRepräsentiert das Ausgabeverzeichnis. -
sourceMapErzeugt eine.map-Datei, die zum Debuggen unserer App sehr nützlich sein kann. -
includeWird verwendet, um die einzuschließende Dateiliste anzugeben.
-
Die Konfigurationsoptionen variieren je nach Bedarf eines Projekts. Möglicherweise müssen Sie die Tabelle mit den TypeScript-Optionen überprüfen, um herauszufinden, was zu Ihrem Projekt passt.
Wir haben nur die erforderlichen Maßnahmen ergriffen, um die Dinge vorzubereiten. Unser nächster Schritt besteht darin, eine Datei zu TypeScript zu migrieren.
3. Beginnen Sie mit einer einfachen Komponente
Nutzen Sie die Fähigkeit von TypeScript, schrittweise übernommen zu werden. Gehen Sie eine Datei nach der anderen in Ihrem eigenen Tempo vor. Tun Sie, was für Sie und Ihr Team sinnvoll ist. Versuchen Sie nicht, alles auf einmal anzugehen.
Um dies richtig umzuwandeln, müssen wir zwei Dinge tun:
- Ändern Sie die Dateierweiterung in
.tsx. - Fügen Sie die Typanmerkung hinzu (was einige TypeScript-Kenntnisse erfordern würde).
4. Dateierweiterungen in .tsx
In einer großen Codebasis kann es ermüdend erscheinen, Dateien einzeln umzubenennen.
Benennen Sie mehrere Dateien unter macOS um
Das Umbenennen mehrerer Dateien kann eine Zeitverschwendung sein. So können Sie es auf einem Mac machen. Klicken Sie mit der rechten Maustaste (oder Ctrl + Klick oder klicken Sie mit zwei Fingern gleichzeitig auf dem Trackpad, wenn Sie ein MacBook verwenden) auf den Ordner, der die Dateien enthält, die Sie umbenennen möchten. Klicken Sie dann auf „Im Finder anzeigen“. Wählen Sie im Finder alle Dateien aus, die Sie umbenennen möchten. Klicken Sie mit der rechten Maustaste auf die ausgewählten Dateien und wählen Sie „X Elemente umbenennen…“. Dann sehen Sie so etwas:

Geben Sie die Zeichenfolge ein, die Sie finden möchten, und die Zeichenfolge, durch die Sie diese gefundene Zeichenfolge ersetzen möchten, und klicken Sie auf „Umbenennen“. Getan.
Benennen Sie mehrere Dateien unter Windows um
Das Umbenennen mehrerer Dateien unter Windows würde den Rahmen dieses Tutorials sprengen, aber eine vollständige Anleitung ist verfügbar. Normalerweise würden Sie nach dem Umbenennen der Dateien Fehler erhalten; Sie müssen nur die Typanmerkungen hinzufügen. Sie können dies in der Dokumentation auffrischen.
Wir haben behandelt, wie man TypeScript in einer React-App einrichtet. Lassen Sie uns nun mit TypeScript eine Episodenauswahl-App für Money Heist erstellen.
Wir werden die grundlegenden Typen von TypeScript nicht behandeln. Es ist erforderlich, die Dokumentation durchzugehen, bevor Sie mit diesem Lernprogramm fortfahren.
Zeit zum Bauen
Damit sich dieser Prozess weniger entmutigend anfühlt, werden wir ihn in Schritte unterteilen, die es uns ermöglichen, die App in einzelnen Abschnitten zu erstellen. Hier sind alle Schritte, die wir unternehmen werden, um die Episodenauswahl für Haus des Geldes zu erstellen:
- Erstellen Sie ein Gerüst für eine Create React App.
- Folgen abrufen.
- Erstellen Sie die entsprechenden Typen und Schnittstellen für unsere Episoden in
interface.ts. - Richten Sie den Store zum Abrufen von Episoden in
store.tsx. - Erstellen Sie die Aktion zum Abrufen von Episoden in
action.ts. - Erstellen Sie eine
EpisodeList.tsx-Komponente, die die abgerufenen Episoden enthält. - Importieren Sie die
EpisodesList-Komponente mitReact Lazy and Suspenseauf unsere Homepage.
- Erstellen Sie die entsprechenden Typen und Schnittstellen für unsere Episoden in
- Folgen hinzufügen.
- Store einrichten, um Episoden in
store.tsx. - Erstellen Sie die Aktion zum Hinzufügen von Episoden in
action.ts.
- Store einrichten, um Episoden in
- Folgen entfernen.
- Richten Sie den Store zum Löschen von Episoden in
store.tsx. - Erstellen Sie die Aktion zum Löschen von Folgen in
action.ts.
- Richten Sie den Store zum Löschen von Episoden in
- Lieblingsfolge.
- Importieren Sie die
EpisodesListKomponente in die Lieblingsepisode. - Render
EpisodesListinnerhalb der Lieblingsepisode.
- Importieren Sie die
- Verwenden von Reach Router für die Navigation.
Reaktion einrichten
Der einfachste Weg, React einzurichten, ist die Verwendung der Create React App. Create React App ist eine offiziell unterstützte Möglichkeit, einseitige React-Anwendungen zu erstellen. Es bietet ein modernes Build-Setup ohne Konfiguration.
Wir werden es verwenden, um die Anwendung zu booten, die wir erstellen werden. Führen Sie in Ihrer CLI den folgenden Befehl aus:
npx create-react-app react-ts-app && cd react-ts-app Starten Sie nach erfolgreicher Installation den React-Server, indem Sie npm start .

Schnittstellen und Typen in Typoskript verstehen
Schnittstellen in TypeScript werden verwendet, wenn wir Objekteigenschaften Typen zuweisen müssen. Daher würden wir Schnittstellen verwenden, um unsere Typen zu definieren.
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 } Beim Kompilieren des obigen Codes würden wir diesen Fehler sehen: „Arten des salary sind nicht kompatibel. Der Typ string ist dem Typ number nicht zuweisbar.“
Solche Fehler treten in TypeScript auf, wenn einer Eigenschaft oder Variablen ein anderer als der definierte Typ zugewiesen wird. Das obige Snippet bedeutet insbesondere, dass der salary ein string anstelle eines number zugewiesen wurde.
Lassen Sie uns eine interface.ts -Datei in unserem src -Ordner erstellen. Kopieren Sie diesen Code und fügen Sie ihn ein:
/** |-------------------------------------------------- | 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> }Es hat sich bewährt, dem Namen der Schnittstelle ein „I“ hinzuzufügen. Es macht den Code lesbar. Sie können sich jedoch entscheiden, es auszuschließen.
IEpisode-Schnittstelle
Unsere API gibt eine Reihe von Eigenschaften wie airstamp airdate airtime , id , image , name , number , runtime , season , summary und url zurück . Daher haben wir eine IEpisode -Schnittstelle definiert und die entsprechenden Datentypen auf die Objekteigenschaften gesetzt.
IState-Schnittstelle
Unsere IState Schnittstelle hat episodes bzw. favorites und eine Array<IEpisode> -Schnittstelle.
Aktion
Die Eigenschaften der IAction Schnittstelle sind payload und type . Die type Eigenschaft hat einen String-Typ, während die Payload einen Array | any -Typ hat Array | any .
Beachten Sie, dass Array | any Array | any bedeutet ein Array der Episodenschnittstelle oder einen beliebigen Typ.
Der Dispatch -Typ ist auf React.Dispatch und eine <IAction> -Schnittstelle festgelegt. Beachten Sie, dass React.Dispatch gemäß der @types/react -Codebasis der Standardtyp für die dispatch -Funktion ist, während <IAction> ein Array der Interface-Aktion ist.
Außerdem verfügt Visual Studio Code über einen TypeScript-Checker. Durch bloßes Hervorheben oder Bewegen des Mauszeigers über Code ist es intelligent genug, um den entsprechenden Typ vorzuschlagen.

Mit anderen Worten, damit wir unsere Schnittstelle über unsere Apps hinweg nutzen können, müssen wir sie exportieren. Bisher haben wir unseren Speicher und unsere Schnittstellen, die den Typ unseres Objekts enthalten. Lassen Sie uns jetzt unseren Shop erstellen. Beachten Sie, dass die anderen Schnittstellen denselben Konventionen wie die erläuterten folgen.
Folgen abrufen
Erstellen eines Shops
Um unsere Episoden abzurufen, benötigen wir einen Speicher, der den Anfangszustand der Daten enthält und der unsere Reducer-Funktion definiert.
Wir verwenden den useReducer Hook, um das einzurichten. Erstellen Sie eine store.tsx -Datei in Ihrem src -Ordner. Kopieren Sie den folgenden Code und fügen Sie ihn ein.
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} }
Im Folgenden sind die Schritte aufgeführt, die wir zum Erstellen des Shops unternommen haben:
- Bei der Definition unseres Shops benötigen wir den
useReducerHook und diecreateContextAPI von React, weshalb wir sie importiert haben. - Wir
IStateundIActionaus./types/interfacesimportiert. - Wir haben ein
initialState-Objekt mit dem TypIStateund Eigenschaften von Episoden und Favoriten deklariert, die beide jeweils auf ein leeres Array gesetzt sind. - Als Nächstes haben wir eine
Store-Variable erstellt, die die MethodecreateContextund an dieinitialState.
Der Methodentyp createContext ist <IState | any> <IState | any> , was bedeutet, dass es sich um einen Typ von <IState> oder any handeln kann. Wir werden den any Typ sehen, der in diesem Artikel häufig verwendet wird.
- Als nächstes haben wir eine
reducer-Funktion deklariert undstateundactionals Parameter übergeben. Diereducer-Funktion hat eine switch-Anweisung, die den Wert vonaction.type. Wenn der WertFETCH_DATAist, wird ein Objekt zurückgegeben, das eine Kopie unseres Status(...state)und des Episodenstatus enthält, der unsere Aktionsnutzdaten enthält. - In der switch-Anweisung geben wir einen state of
defaultzurück.
Beachten Sie, dass die state und action in der Reducer-Funktion IState bzw. IAction Typen haben. Außerdem hat die reducer -Funktion einen Typ von IState .
- Zuletzt haben wir eine
StoreProviderFunktion deklariert. Dadurch erhalten alle Komponenten in unserer App Zugriff auf den Store. - Diese Funktion nimmt
childrenals Requisite, und innerhalb derStorePrivderFunktion haben wir denuseReducerHook deklariert. - Wir haben
stateunddispatchdestrukturiert. - Um unseren Shop für alle Komponenten zugänglich zu machen, haben wir einen Objektwert mit
stateunddispatchübergeben.
Der state , der unsere Episoden und Favoriten enthält, wird von anderen Komponenten zugänglich gemacht, während der dispatch eine Funktion ist, die den Status ändert.
- Wir werden
StoreundStoreProvider, damit sie in unserer gesamten Anwendung verwendet werden können.
Aktion.ts erstellen
Wir müssen Anfragen an die API stellen, um die Episoden abzurufen, die dem Benutzer gezeigt werden. Dies geschieht in einer Aktionsdatei. Erstellen Sie eine Action.ts -Datei und fügen Sie dann den folgenden Code ein:
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 }) }Zuerst müssen wir unsere Schnittstellen importieren, damit sie in dieser Datei verwendet werden können. Folgende Schritte wurden unternommen, um die Aktion zu erstellen:
- Die Funktion
fetchDataActionnimmtdispatch-Requisiten als Parameter. - Da unsere Funktion asynchron ist, würden wir
asyncundawaitverwenden. - Wir erstellen eine Variable (
URL), die unseren API-Endpunkt enthält. - Wir haben eine weitere Variable namens
data, die die Antwort von der API enthält. - Dann speichern wir die JSON-Antwort in
dataJSON, nachdem wir die Antwort im JSON-Format durch den Aufruf vondata.json()haben. - Zuletzt geben wir eine Dispatch-Funktion zurück, die eine Eigenschaft vom
typeund eine Zeichenfolge vonFETCH_DATA. Es hat auch einepayload()._embedded.episodesist das Array des Episodenobjekts von unseremendpoint.
Beachten Sie, dass die Funktion fetchDataAction unseren Endpunkt abruft, ihn in JSON -Objekte konvertiert und die Dispatch-Funktion zurückgibt, die den zuvor im Store deklarierten Status aktualisiert.
Der exportierte Versandtyp ist auf React.Dispatch . Beachten Sie, dass React.Dispatch der Standardtyp für die Dispatch-Funktion gemäß der @types/react -Codebasis ist, während <IAction> ein Array der Schnittstellenaktion ist.
EpisodesList-Komponente
Um die Wiederverwendbarkeit unserer App zu gewährleisten, speichern wir alle abgerufenen Episoden in einer separaten Datei und importieren die Datei dann in unsere homePage Komponente.
Erstellen Sie im components eine EpisodesList.tsx -Datei, kopieren Sie den folgenden Code und fügen Sie ihn ein:
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- Wir importieren
IEpisodeundIPropsausinterfaces.tsx. - Als Nächstes erstellen wir eine
EpisodesList-Funktion, die Requisiten verwendet. Die Requisiten haben den TypIProps, während die Funktion den TypArray<JSX.Element>hat.
Visual Studio Code schlägt vor, dass unser Funktionstyp als JSX.Element[] geschrieben wird.

Während Array<JSX.Element> gleich JSX.Element[] ist, wird Array<JSX.Element> als generische Identität bezeichnet. Daher wird das generische Muster in diesem Artikel häufig verwendet.
- Innerhalb der Funktion destrukturieren wir die
episodesvonprops, dieIEpisodeals Typ hat.
Lesen Sie mehr über die generische Identität. Dieses Wissen wird im weiteren Verlauf benötigt.
- Wir haben die Requisiten der
episodeszurückgegeben und durchgemappt, um ein paar HTML-Tags zurückzugeben. - Der erste Abschnitt enthält den
keyepisode.idund einenclassNamevonepisode-box, der später erstellt wird. Wir wissen, dass unsere Episoden Bilder haben; daher das Image-Tag. - Das Bild hat einen ternären Operator, der prüft, ob entweder ein
episode.imageoder einepisode.image.medium. Andernfalls zeigen wir eine leere Zeichenfolge an, wenn kein Bild gefunden wird. Außerdem haben wirepisode.namein ein div eingefügt.
Im section zeigen wir die Staffel, zu der eine Episode gehört, und ihre Nummer. Wir haben eine Schaltfläche mit dem Text Fav . Wir haben die EpisodesList -Komponente exportiert, damit wir sie in unserer App verwenden können.
Homepage-Komponente
Wir möchten, dass die Homepage den API-Aufruf auslöst und die Episoden mithilfe der von uns erstellten EpisodesList -Komponente anzeigt. Erstellen Sie im components die HomePage -Komponente, kopieren Sie den folgenden Code und fügen Sie ihn ein:
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- Wir importieren
useContext,useEffect,lazyundSuspensevon React. Die importierte App-Komponente ist das Fundament, auf dem alle anderen Komponenten den Wert des Stores erhalten müssen. - Wir importieren auch
Store,IEpisodePropsundFetchDataActionaus ihren jeweiligen Dateien. - Wir importieren die
EpisodesList-Komponente mit derReact.lazyFunktion, die in React 16.6 verfügbar ist.
React Lazy Loading unterstützt die Code-Splitting-Konvention. Daher wird unsere EpisodesList Komponente dynamisch geladen, anstatt sofort geladen zu werden, wodurch die Leistung unserer App verbessert wird.
- Wir destrukturieren den
stateunddispatchals Requisiten aus demStore. - Das kaufmännische Und (&&) im
useEffectHook prüft, ob unser Episodenstatusempty(oder gleich 0) ist. Andernfalls geben wir die FunktionfetchDataActionzurück. - Zuletzt geben wir die
AppKomponente zurück. Darin verwenden wir denSuspense-Wrapper und setzen denfallbackauf ein div mit demloading. Dies wird dem Benutzer angezeigt, während wir auf die Antwort von der API warten. - Die
EpisodesList-Komponente wird bereitgestellt, wenn die Daten verfügbar sind, und die Daten, die dieepisodesenthalten, sind das, was wir darin verteilen.
Richten Sie Index.txs ein
Die Homepage -Komponente muss dem StoreProvider . Wir müssen das in der index tun. Benennen Sie index.js in index.tsx um und fügen Sie den folgenden Code ein:
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') ) Wir importieren StoreProvider , HomePage und index.css aus ihren jeweiligen Dateien. 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.
Wir sind von weit hergekommen. 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.
Wir werden EpisodeList.tsx weitere Schnipsel hinzufügen. Kopieren Sie den markierten Code und fügen Sie ihn ein:
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 } = storereturn 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
Wir togglefavaction , favorites und store als Requisiten ein und destrukturieren state , eine dispatch aus dem Store. Um unsere Lieblingsepisode auszuwählen, binden wir die toggleFavAction Methode in ein onClick -Ereignis ein und übergeben die state , dispatch und episode als Argumente an die Funktion.
Zuletzt durchlaufen wir den favorite , um zu prüfen, ob fav.id (Favoriten-ID) mit episode.id . Wenn dies der Fall ist, schalten wir zwischen dem Unfav und dem Fav -Text um. Dies hilft dem Benutzer zu wissen, ob er diese Episode favorisiert hat oder nicht.
Wir nähern uns dem Ende. Aber wir brauchen immer noch eine Seite, auf der Lieblingsepisoden verlinkt werden können, wenn der Benutzer eine der Episoden auf der Startseite auswählt.
Wenn Sie so weit gekommen sind, klopfen Sie sich auf die Schulter.
Favpage-Komponente
Erstellen Sie im components eine FavPage.tsx -Datei. Kopieren Sie den folgenden Code und fügen Sie ihn ein:
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> ) } Um die Logik hinter der Auswahl von Lieblingsepisoden zu erstellen, haben wir einen kleinen Code geschrieben. Wir importieren lazy und Suspense von React. Wir importieren auch Store , IEpisodeProps und toggleFavAction aus ihren jeweiligen Dateien.
Wir importieren unsere EpisodesList -Komponente mit der React.lazy Funktion. Zuletzt geben wir die App Komponente zurück. Darin verwenden wir den Suspense -Wrapper und setzen einen Fallback auf ein div mit dem Ladetext.
Dies funktioniert ähnlich wie die Homepage Komponente. Diese Komponente greift auf den Store zu, um die vom Benutzer favorisierten Episoden zu erhalten. Anschließend wird die Liste der Episoden an die EpisodesList Komponente übergeben.
Fügen wir der Datei HomePage.tsx ein paar weitere Ausschnitte hinzu.
Fügen Sie die toggleFavAction aus ../Actions . Fügen Sie auch die toggleFavAction Methode als Requisiten hinzu.
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
Unsere FavPage muss verlinkt werden, also brauchen wir einen Link in unserem Header in App.tsx . Um dies zu erreichen, verwenden wir Reach Router, eine Bibliothek ähnlich wie React Router. William Le erklärt die Unterschiede zwischen Reach Router und React Router.
Führen Sie in Ihrer CLI npm install @reach/router @types/reach__router . Wir installieren sowohl die Reach-Router-Bibliothek als auch Reach reach-router Typen.
Importieren Sie nach erfolgreicher Installation den Link von @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
Wir destrukturieren den Speicher von useContext . Schließlich hat unser Zuhause einen Link und einen Pfad zu / , während unser Favorit einen Pfad zu /faves hat.
{state.favourites.length} prüft die Anzahl der Episoden in den Favoritenstaaten und zeigt sie an.
Schließlich importieren wir in unsere index.tsx -Datei die FavPage bzw. HomePage -Komponenten und packen sie in den Router ein.
Kopieren Sie den markierten Code in den vorhandenen Code:
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.pageComponentReactDOM.render( <StoreProvider><Router> <RouterPage pageComponent={<HomePage />} path='/' /> <RouterPage pageComponent={<FavPage />} path='/faves' /> </Router></StoreProvider>, document.getElementById('root') )
Sehen wir uns nun an, wie das implementierte ADD_FAV funktioniert.

Favoritenfunktion entfernen
Schließlich fügen wir die Funktion „Episode entfernen“ hinzu, sodass wir beim Klicken auf die Schaltfläche zwischen dem Hinzufügen oder Entfernen einer Lieblingsepisode umschalten. Wir zeigen die Anzahl der hinzugefügten oder entfernten Episoden in der Kopfzeile an.
LADEN
Um die Funktion „Lieblingsfolge entfernen“ zu erstellen, werden wir einen weiteren Fall in unserem Shop hinzufügen. Gehen Sie also zu Store.tsx und fügen Sie den hervorgehobenen Code hinzu:
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} }
Wir fügen noch einen weiteren Fall namens REMOVE_FAV und geben ein Objekt zurück, das die Kopie unseres initialState . Außerdem enthält der favorites die Aktionsnutzlast.
AKTION
Kopieren Sie den folgenden hervorgehobenen Code und fügen Sie ihn in 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 typeexport 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) }
Wir importieren die IState Schnittstelle aus ./types/interfaces , da wir sie als Typ an die state in der Funktion toggleFavAction müssen.
Eine episodeInFav Variable wird erstellt, um zu prüfen, ob es eine Folge gibt, die im favorites vorhanden ist.
Wir filtern den Status der Favoriten, um zu prüfen, ob eine Favoriten-ID nicht gleich einer Episoden-ID ist. Somit wird dem dispatchObj ein Typ von REMOVE_FAV und eine Nutzlast von favWithoutEpisode neu zugewiesen.
Sehen wir uns das Ergebnis unserer App in der Vorschau an.
Fazit
In diesem Artikel haben wir gesehen, wie man TypeScript in einem React-Projekt einrichtet und wie man ein Projekt von Vanilla React zu TypeScript migriert.
Wir haben auch eine App mit TypeScript und React erstellt, um zu sehen, wie TypeScript in React-Projekten verwendet wird. Ich vertraue darauf, dass Sie ein paar Dinge lernen konnten.
Bitte teilen Sie Ihr Feedback und Ihre Erfahrungen mit TypeScript im Kommentarbereich unten mit. Ich würde gerne sehen, was Sie sich einfallen lassen!
Das unterstützende Repository für diesen Artikel ist auf GitHub verfügbar.
Verweise
- „So migrieren Sie eine React-App zu TypeScript“, Joe Previte
- „Warum und wie Sie TypeScript in Ihrer React-App verwenden?“, Mahesh Haldar
