Typescript
UWAGA! Ponieważ nastąpił połączenie React z Typescript okazało się wyjątkowo udane, nastąpił znaczący rozwój tego oprogramowania, a poniższe opisy nieco się zdezaktualizowały. Dlatego powstał nowy rozdział książki poświęcony wyłącznie programowaniu w React i Typescript. Zobaczymy w nim, że to co poniżej opisano, można zrobić dużoprościej.
Aplikacje React można tworzyć w Ttypescript. Wymaga to w sumie niewielkich modyfikacji.
Przede wszystkim musimy zbudować projekt "ręcznie" - ewentualnie korzystając z gotowych szkieletów takich jak https://github.com/basarat/react-typescript.git
Konfiguracja projektu
Aby zbydować projekt, powinniśmy wykonać następujące działania:
1) Zainicjowanie projektu:
yarn init
2) Zainstalowanie typescript, react i webpack:
yarn add typescript react react-dom @types/react @types/react-dom
yarn add webpack webpack-dev-server ts-loader
yarn add webpack-cli -D
3) Modyfikacja utworzonego pliku package.json.
Nie jest nam potrzebny parametr "main", możemy za to dodać definicje skryptów uruchomienia testowego i budowania aplikacji (przy pomocy webpack):
"scripts": {
"build": "webpack -p",
"start": "webpack-dev-server -d --content-base ./public"
},
4) Konfiguracja webpack.config.js
module.exports = {
entry: './src/index.tsx',
output: {
path: __dirname + '/public',
filename: 'build/app.js'
},
resolve: {
extensions: ['.ts', '.tsx', '.js']
},
module: {
rules: [
{ test: /\.tsx?$/, loader: 'ts-loader' }
]
}
}
W tym przykładzie możemy zmieniać położenie modułu startowego (entry) i definicję wyjścia.
5) Konfiguracja Typescript - plik tsconfig.json:
{
"compilerOptions": {
"sourceMap": true,
"module": "commonjs",
"target": "es5",
"jsx": "react",
"lib": [
"dom",
"es6"
]
},
"include": [
"src"
],
"compileOnSave": false
}
Programowanie
Ponieważ Typescript jest nadzbiorem Javascript - konieczne zmiany - poza użyciem typów - nie są wielkie.
w miejsce:
import React from 'react';
import ReactDOM from 'react-dom';
ma być:
import * as React from 'react';
import * as ReactDOM from 'react-dom';
Potem używamy identyfikatorów z odpowiednim przedrostkiem (na przykład ReactDOM.render).
Pliki Typescript w tórych stosujemy JSX powinny mieć rozszerzenia nazwy '.tsx'. Wówczas przy imporcie nie musimy podawać rozszerzeń. Najprostszy przykład możemy stworzyć na bazie https://github.com/tenarjw/react-intro-by-example/tree/master/typescript/simple
W pliku src/index.tsx wpisujemy:
import * as React from 'react';
import * as ReactDOM from 'react-dom';
ReactDOM.render(
<div>Hello World</div>,
document.getElementById("root")
);
Uruchamiamy:
yarn install
yarn start
Sprawdzamy działanie na http://127.0.0.1:8080
Własne komponenty
Najprostszy element React definiujemy tak jak w Javascript:
const Najprostszy = (props) => (<p>Najprostszy</p>);
Jeśli chcemy przekazać własności poprzez props i zadeklarować typtego props, wykorzystujemy interfejs interfejs React.SFC
type Props2 = {
nazwa: string;
}
const KomponentSFC : React.SFC<Props2> = (props) => {
return <div><b>Bezstanowy z parametrem: </b>
Nazwa = {props.nazwa}</div>
}
Użycie tych komponentów jest takie samo jak w Javascript:
<Najprostszy />
<KomponentSFC nazwa="test SFC" />
Badziej złożony przypadek - to komponent z wewnetrzym stanem i obsługą zdarzeń:
type Props3 = {
opis: string;
srodek: React.ReactNode;
}
type State3 = {
licznik : number;
}
class Komponent3 extends React.Component<Props3, {}> {
state : State3;
constructor(props) {
super(props);
this.state = { licznik : 0}
}
private klik = (event: React.MouseEvent<HTMLButtonElement>) : void =>
{ this.setState({licznik: this.state.licznik+1})}
render() {
return <div><br />Komponent z licznikiem
i parametrem JSX (link)<br />
opis= {this.props.opis}:<br />
parametr JSX = {this.props.srodek}<br />
<button onClick={ this.klik }>Kliknij [{this.state.licznik}]
</button>
</div>
}
}
Jak widać - jedyną zmianą jest dodanie typów.
Natomiast samo użycie komponentu nie ulega zmianie:
<Komponent3 opis="test JSX" srodek={<a href="#">OK</a>}/>
Ostatni z przykładów dotyczy komponentu z wartością domyślną własności:
class Hello2 extends React.Component<{
imie?: string,
nazwisko: string
}> {
static defaultProps = {
imie: 'NN'
}
render() {
const imie = this.props.imie!;
return (
<div>
<br />
Z domyślną wartością
<div>{imie}</div>
<div>{this.props.nazwisko}</div>
</div>
);
}
}
Znak zapytania oznacza możliwość braku parametrów. natomiast defaultProps może zawiera wartości domyślne. Użycie:
<Hello2 nazwisko='' />
Spowoduje wyświetlenie NN
Zobacz kompletny przykład [039]