Verwenden von Typoskript mit Reagieren - Ein Leitfaden für Anfänger

Freunde, am Vorabend des Wochenendes möchten wir Ihnen eine weitere interessante Veröffentlichung vorstellen, die mit dem Start einer neuen Gruppe im Kurs "JavaScript Developer" zusammenfallen soll .



Nachdem ich in den letzten Monaten React-Anwendungen und -Bibliotheken mit Typescript entwickelt hatte, beschloss ich, einige der Dinge zu teilen, die ich in dieser Zeit gelernt hatte. In diesem Handbuch werde ich Ihnen die Vorlagen erläutern, die ich in 80% der Fälle für Typescript und React verwende.

Sollte ich Typoskript für die Entwicklung von Reaktionsanwendungen lernen? Wert, immer noch wert! Für mich selbst wurde mir klar, dass striktes Tippen dazu führt, dass viel zuverlässigerer Code geschrieben und schnell entwickelt wird, insbesondere bei großen Projekten. Zuerst werden Sie wahrscheinlich enttäuscht sein, aber während Sie arbeiten, werden Sie feststellen, dass zumindest eine minimale Vorlage wirklich sehr hilfreich ist.

Und wenn Sie an etwas hängen bleiben, denken Sie daran, dass Sie immer so etwas eingeben können. Jeder ist dein neuer Freund. Und jetzt kommen wir direkt zu Beispielen.

Ihre Kernreaktionskomponente mit Typoskript


Wie sieht die Standardreaktionskomponente auf Typoskript aus? Vergleichen wir es mit der Reaktionskomponente in Javascript.

import React from 'react' import PropTypes from 'prop-types' export function StandardComponent({ children, title = 'Dr.' }) { return ( <div> {title}: {children} </div> ) } StandardComponent.propTypes = { title: PropTypes.string, children: PropTypes.node.isRequired, } 

Und jetzt die Typoskript-Version:

 import * as React from 'react' export interface StandardComponentProps { title?: string children: React.ReactNode } export function StandardComponent({ children, title = 'Dr.', }: StandardComponentProps) { return ( <div> {title}: {children} </div> ) } 

Sehr ähnlich, oder? Wir haben propTypes durch die propTypes Schnittstelle ersetzt.

Der prop bleibt optional, während die Requisite des Erben weiterhin benötigt wird. Wir haben unsere Schnittstelle exportiert, falls eine andere Komponente einen Link dazu benötigt.

Erweitern von Standard-HTML-Attributen


Wenn die übergeordnete Komponente zusätzliche typisierte div Attribute wie aria-hidden , style oder className , können wir sie in der interface oder die integrierte Schnittstelle erweitern. Im folgenden Beispiel sagen wir, dass unsere Komponente zusätzlich zum Header und den Nachkommen alle Standard- div Eigenschaften akzeptiert.

 import * as React from 'react' export interface SpreadingExampleProps extends React.HTMLAttributes<HTMLDivElement> { title?: string children: React.ReactNode } export function SpreadingExample({ children, title = 'Dr.', ...other }: SpreadingExampleProps) { return ( <div {...other}> {title}: {children} </div> ) } 

Ereignisbehandlung


Wir können Ereignishandler typisieren, um sicherzustellen, dass das Ereignisargument vom richtigen Typ ist. Das folgende Beispiel zeigt verschiedene Möglichkeiten, um dieses Ziel zu erreichen:

 export interface EventHandlerProps { onClick: (e: React.MouseEvent) => void } export function EventHandler({ onClick }: EventHandlerProps) { // handle focus events in a separate function function onFocus(e: React.FocusEvent) { console.log('Focused!', e.currentTarget) } return ( <button onClick={onClick} onFocus={onFocus} onKeyDown={e => { // When using an inline function, the appropriate argument signature // is provided for us }} > Click me! </button> ) } 

Sie sind sich nicht sicher, welche Argument-Signatur verwendet werden soll? Bewegen Sie den Mauszeiger im Editor über die entsprechende Eigenschaft des Ereignishandlers.

Verwendung von Generika mit Reaktionskomponenten


Dies ist eine erweiterte Funktion, aber sie ist sehr leistungsfähig. In der Regel definieren Sie Datentypen in Reaktionskomponenten mit bestimmten Attributen. Angenommen, Ihre Komponente benötigt ein profile .

 interface ProfileType { name: string image: string age: number | null } interface ProfilesProps { profiles: Array<ProfileType> } function Profiles(props: ProfilesProps) { // render a set of profiles } 

Stellen wir uns nun vor, Sie haben eine Komponente, die ein Array eines beliebigen Typs akzeptieren kann. Generika sind wie das Versenden von Paketen. Der Kurier (unsere Komponente) muss den Inhalt des von Ihnen gesendeten Pakets nicht kennen, aber der Absender (übergeordnete Komponente) erwartet, dass der Empfänger den von ihm gesendeten Inhalt erhält.

Wir implementieren es so:

 interface GenericsExampleProps<T> { children: (item: T) => React.ReactNode items: Array<T> } export function GenericsExample<T>({ items, children, }: GenericsExampleProps<T>) { return ( <div> {items.map(item => { return children(item) })} </div> ) } 

Ein etwas seltsames Beispiel ... dennoch zeigt es die Essenz. Die Komponente akzeptiert ein Array von Elementen eines beliebigen Typs, durchläuft es und ruft die children Funktion als Renderfunktion mit einem Array-Element auf. Wenn unsere übergeordnete Komponente einen Render-Renderer als Erben bereitstellt, wird das Element korrekt eingegeben!

Verstehst du nicht Es ist in Ordnung. Ich selbst habe Generika bis zum Ende nicht herausgefunden, aber es ist unwahrscheinlich, dass Sie sie gründlich verstehen müssen. Je mehr Sie jedoch mit typescript , desto sinnvoller wird es.

Haken tippen


Haken funktionieren meistens sofort. Die beiden Ausnahmen können nur useRef und useReducer . Das folgende Beispiel zeigt, wie wir refs eingeben können.

 import * as React from 'react' interface HooksExampleProps {} export function HooksExample(props: HooksExampleProps) { const [count, setCount] = React.useState(0) const ref = React.useRef<HTMLDivElement | null>(null) // start our timer React.useEffect( () => { const timer = setInterval(() => { setCount(count + 1) }, 1000) return () => clearTimeout(timer) }, [count] ) // measure our element React.useEffect( () => { if (ref.current) { console.log(ref.current.getBoundingClientRect()) } }, [ref] ) return <div ref={ref}>Count: {count}</div> } 

Unser Status wird automatisch eingegeben, aber wir haben ref manuell eingegeben, um anzuzeigen, dass er null oder ein div Element enthält. Wenn wir in der Funktion useEffect auf ref useEffect , müssen wir sicherstellen, dass es nicht null .

Getriebetyp


Das Getriebe ist etwas komplizierter, aber wenn es richtig getippt ist, ist das großartig.

 // Yeah, I don't understand this either. But it gives us nice typing // for our reducer actions. type Action<K, V = void> = V extends void ? { type: K } : { type: K } & V // our search response type interface Response { id: number title: string } // reducer actions. These are what you'll "dispatch" export type ActionType = | Action<'QUERY', { value: string }> | Action<'SEARCH', { value: Array<Response> }> // the form that our reducer state takes interface StateType { searchResponse: Array<Response> query: string } // our default state const initialState: StateType = { searchResponse: [], query: '', } // the actual reducer function reducer(state: StateType, action: ActionType) { switch (action.type) { case 'QUERY': return { ...state, query: action.value, } case 'SEARCH': return { ...state, searchResponse: action.value, } } } interface ReducerExampleProps { query: string } export function ReducerExample({ query }: ReducerExampleProps) { const [state, dispatch] = React.useReducer(reducer, initialState) React.useEffect( () => { if (query) { // emulate async query setTimeout(() => { dispatch({ type: 'SEARCH', value: [{ id: 1, title: 'Hello world' }], }) }, 1000) } }, [query] ) return state.searchResponse.map(response => ( <div key={response.id}>{response.title}</div> )) } 

Verwenden von typeof und keyof zum Typisieren von Komponentenoptionen


Angenommen, wir benötigen eine Schaltfläche mit einem anderen Erscheinungsbild, die jeweils in einem Objekt mit einer Reihe von Schlüsseln und Stilen definiert ist, zum Beispiel:

 const styles = { primary: { color: 'blue', }, danger: { color: 'red', }, } 

Unsere Schaltflächenkomponente sollte eine Typeneigenschaft akzeptieren, die sein kann
Beliebiger Schlüssel aus dem styles (z. B. "primär" oder "Gefahr" ). Wir können es ganz einfach eingeben:

 const styles = { primary: { color: 'blue', }, danger: { color: 'red', }, } // creates a reusable type from the styles object type StylesType = typeof styles // ButtonType = any key in styles export type ButtonType = keyof StylesType interface ButtonProps { type: ButtonType } export function Button({ type = 'primary' }: ButtonProps) { return <button style={styles[type]}>My styled button</button> } 

Diese Beispiele helfen Ihnen dabei, 80% des Weges zu gehen. Wenn Sie nicht weiterkommen, lohnt es sich oft
Schauen Sie sich einfach die vorhandenen Open Source-Beispiele an.

Die Sancho-Benutzeroberfläche besteht aus einer Reihe von Reaktionskomponenten.
gebaut mit Typoskript und Emotion.
Blueprint ist ein weiterer Satz von Komponenten
react auf typescript .

Nun, nach etablierter Tradition warten wir auf Ihre Kommentare.

Source: https://habr.com/ru/post/de456124/


All Articles