curgere este un verificator de tip static pentru Javascript. Această postare este destinată celor care au auzit de la Flow, dar încă nu am încercat să-l folosim în cadrul unei aplicații React. Dacă este prima dată când auziți de Flow, vă pot recomanda aceste patru postări de Preethi Kasireddy ca o introducere excelentă.
Un lucru grozav despre Flow este că este posibil să îl utilizați în mod incremental. Nu trebuie să refactorizați complet un proiect existent pentru a începe să îl utilizați. Poate fi adăugat doar la fișierele noi sau poate fi încercat încet în fișierele existente pentru a vedea dacă oferă beneficii proiectului dvs. specific înainte de a se angaja complet.
Deoarece configurarea unui nou instrument poate fi adesea cea mai provocatoare, în acest post vom lua un proiect existent și vom parcurge configurarea adăugării Flow. O introducere generală a sintaxei este tratată în a doua dintre postările lui Preethi și în Documente de flux sunt, de asemenea, foarte lizibile.
Vom folosi acest lucru exemplu repo, cu două directoare pentru pre- și post- Flow. Folosește Skyscanner script personalizat Create React App backpack-react-scripts
, asociat cu obiceiul lor Componente pentru rucsac. Aceasta vizează crearea de exemple mai complexe decât fragmentele individuale, dar totuși lizibile, chiar dacă nu le cunoașteți.
Natura exactă a aplicației nu este importantă în comparație cu a vedea diferența dintre implementarea sa fără și cu Curgere. Foarte puține fișiere se schimbă aici, dar sunt adesea cele mai frustrante pentru a obține dreptate!
Să parcurgem fiecare pas și apoi să aruncăm o privire la convertirea componentelor de exemplu.
Conţinut
- 1 Instalați principalele dependențe
- 2 Generați un fluxconfig
- 3 Sincronizați cu alte lintere utilizate
- 4 Flux tastat libdefs
- 5 Conversia componentelor existente
- 6 Verificarea tipului componentelor React importate
- 7 Marcarea elementelor de recuzită ca opțional
- 8 Extensii ESLint, accesorii implicite și soluții de eroare de validare a accesoriilor
- 9 Gânduri finale
Instalați principalele dependențe
Alături de Flow în sine, instalați babel-cli și babel-preset-flow, astfel încât babel să poată elimina adnotările de tip la compilare.
npm install flow-bin babel-cli babel-preset-flow --save-dev
Configurați Babel
Pentru ca acestea să aibă efect creați un .babelrc
sau adăugați la fișierul existent .babelrc
urmând config:
{
"presets": ["flow"]
}
Scripturi de configurare
Dacă folosiți cârlige, cum ar fi un script de testare, vă recomandăm să le actualizați și să adăugați Fluxul de bază scenariu pentru dumneavoastră package.json
:
"scripts": {
"flow": "flow",
"pretest": "npm run flow && npm run lint"
}
Generați un fluxconfig
Dacă rulați fluxul pentru prima dată, puteți genera un șablon .flowconfig
prin alergare npm run flow init
. În exemplul nostru ne putem vedea extinde-l pentru a adăuga următoarele:
Ignorați tiparele
Pentru a evita fluxul analiza modulelor nodului dvs. și a construi ieșirea, acestea pot fi ușor ignorate.
[ignore].*/node_modules/*.*/build/*
Adăugați suport pentru module CSS
Dacă utilizați module CSS, tipul acestora trebuie specificat pentru ca Flow să le înțeleagă, altfel veți primi această eroare:
Acest lucru se face în doi pași. Mai întâi, se adaugă cele de mai jos .flowconfig
:
[libs]
./src/types/global.js // this can be any path and filename you wish
[options]
module.name_mapper="^(.*).scss$" -> 'CSSModule'
module.system=haste
Și în al doilea rând se creează un tip de modul CSS în fișierul menționat în [libs]
.
// @flow
declare module CSSModule {
declare var exports: { [key: string]: string };
declare export default typeof exports;
}
Sincronizați cu alte lintere utilizate
În exemplul de proiect, ESLint este deja utilizat pentru a furniza scame standard. Există câțiva pași de configurare inițiali necesari pentru ca ESLint să se joace frumos cu Flow și alții mai târziu datorită tipurilor specifice utilizate în acest proiect.
Pentru configurarea generală, următorul este adăugat la noi .eslintrc
:
"extends": [
"plugin:flowtype/recommended"
],
"plugins": [
"flowtype"
]
Extensiile specifice acestui exemplu și erorile pe care le evită vor fi acoperite până la sfârșitul acestei postări.
Flux tastat libdefs
Piesa finală de configurare este să vă pregătiți pentru utilizare libdefs
creat folosind flow-typed
Pachet NPM. Aceasta este utilizată pentru a crea definiții pentru modulele de nod instalate și implicit creează aceste fișiere într-un flow-typed/
director.
Noi do doriți să comiteți acest fișier, dar nu doriți ca ESLint să-l scape. Acest lucru creează o problemă, așa cum a fost anterior scriptul nostru de scame în package.json
este setat să ne folosească .gitignore
să știți în timp ce fișierele ESLint ar trebui să ignore, de asemenea:
"lint:js": "eslint . --ignore-path .gitignore --ext .js,.jsx",
Acum vrem să schimbăm acest lucru, deoarece vrem ca ESLint să ignore și ceea ce trebuie creat flow-typed/
director. Ne putem modifica scriptul pentru:
"lint:js": "eslint . --ext .js,.jsx",
Aceasta înseamnă că acum va reveni la utilizarea unui .eslintignore
fișier, deci trebuie să creăm acest lucru, să duplicăm ceea ce este în .gitignore
, și adăugați directorul suplimentar de ignorat la ea.
În cele din urmă, trebuie să instalăm flow-types
. Facem acest lucru la nivel global.
npm install flow-typed -g
libdefs
pot fi definiții complete sau stuburi care acceptă orice tip. O lista de definiții complete este menținut. Pentru a vedea dacă există unul disponibil pentru un pachet pe care îl utilizați
flow-typed install my-dependency@<version.being.used>
și acest lucru îl va adăuga fie la dvs. flow-typed
sau vă solicită să creați un cod folosind
flow-typed create-stub my-dependency@<version.being.used>
Dacă doriți să creați o definiție completă, puteți face acest lucru și, de asemenea, să o contribuiți din nou la depozit, astfel încât să fie disponibilă pentru alți dezvoltatori.
Un proces simplu de urmat este doar crearea libdefs
deoarece sunt cerute în mod specific. Pentru fiecare componentă pe care o convertiți pentru a utiliza Flow adăugați importurile sale folosind flow-typed
în acel moment, nu este necesar să adăugați tipuri pentru toate dependențele dacă nu sunt utilizate în fișiere în care Fluxul este, de asemenea, utilizat.
Conversia componentelor existente
Aceasta este toată configurarea generală realizată, acum ne putem uita la convertirea componentelor noastre de exemplu!
Avem două, o componentă de stare și una de funcție. În general, acestea creează un banner decât are un text și un buton. Pe textul de pe banner se poate face clic pentru a deschide un popover, care conține o listă cu glonț.
Adăugați definiții tip flux
Pentru orice componentă, primul pas este crearea flow-typed
definiții pentru orice import din componenta la care lucrăm.
De exemplu, dacă am avea doar importuri de
import React from 'react';
import BpkButton from 'bpk-component-button';
atunci am încerca:
flow-typed install bpk-component-button@<its.installed.versi
pe>
dacă nu ar fi disponibil și în prezent nu este, atunci am defini definiția sa:
flow-typed create-stub bpk-component-button@latest
În exemplul repo putem vedea lista tuturor definițiilor create pentru componentele la care ne-am mutat folosind Flow. Acestea au fost adăugate pe rând, deoarece fiecare componentă avea Flow integrat cu ele.
Componente funcționale
În exemplul nostru fără Flux folosim PropTypes
pentru unele verificări de tip limitate și capacitatea lor de a defini defaultProps
pentru utilizare în dezvoltare.
Poate arăta puțin complex la prima vedere, dar este relativ puțin ce trebuie să schimbăm pentru a adăuga Flow.
Pentru a transforma acest lucru pentru a utiliza Flow, putem elimina mai întâi PropTypes
import și definiții. // @flow
adnotarea poate fi apoi adăugată la prima linie.
Pentru această componentă vom tasta doar verificarea accesoriilor transmise. Pentru a face acest lucru, vom crea mai întâi un tip Recuzită, mult mai curat decât definirea fiecărui accesoriu în linie.
type Props = {
strings: { [string_key: string]: string },
onClose: Function,
isOpen: boolean,
target: Function,
};
Aici ultimele trei tipuri se explică de la sine. La fel de strings
este un obiect de corzi an obiect ca hartă a fost folosit, verificând fiecare cheie și valoare din obiectul primit pentru a verifica dacă tipurile lor se potrivesc, fără a fi nevoie să specificați exact cheile lor de șir.
Definițiile tipurilor de prop pot fi apoi eliminate împreună cu importul său. Deoarece defaultProps nu sunt legate de acest import, ele pot și ar trebui să rămână. * Consultați comentariile ESLint de închidere pentru orice erori raportate în acest moment.
Componenta ar trebui să arate acum astfel:
Componente de stare
Componentele de stare urmează câteva declarații ușor diferite. Deoarece această componentă este mai complexă, ne vom uita și la declararea tipurilor pentru unele aspecte suplimentare.
Ca și înainte, aruncă mai întâi o privire componentă înainte de a adăuga Flow.
Recuzită și stat
Ca și în componenta funcțională, eliminăm mai întâi propTypes
definiție și import și adăugați fișierul // @flow
adnotare.
Mai întâi vom arunca o privire asupra adăugării de tipuri pentru Accesorii și State. Din nou, vom crea tipuri pentru acestea:
type Props = {
strings: { [string_key: string]: string },
hideBannerClick: Function,
};
type State = {
popoverIsOpen: boolean,
};
și specificați că componenta le va utiliza:
class Banner extends Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
popoverIsOpen: false,
};
...
};
...
};
Apoi am lovit prima noastră diferență între componentele funcționale și stateful, defaultProps
. Într-o componentă Function, acestea au fost declarate așa cum suntem obișnuiți, în componentele Stateful externe Banner.defaultProps
sintaxa este eliminată și, în schimb, valorile implicite sunt declarate în cadrul clasei:
class Banner extends Component<Props, State> {
static defaultProps = {
strings: defaultStrings,
};
constructor(props: Props) {
...
// the below is removed
// Banner.defaultProps = {
// strings: defaultStrings,
// };
Declarațiile constructorului
stringWithPlaceholder
este declarat în cadrul constructorului. Aici nu ne uităm De ce este declarat acolo (vom presupune că există motive întemeiate), ci mai degrabă pentru a vedea dacă fluxul poate fi adăugat fără modificări la codul existent.
Dacă vom rula în starea sa existentă, vom întâlni eroarea Cannot get this.stringWithPlaceholder because property stringWithPlaceholder is missing in Banner [1]
.
Pentru a remedia acest lucru, trebuie să adăugăm o singură linie în interiorul blocului clasei Banner, chiar sub și în afara constructorului:
class Banner extends Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
popoverIsOpen: false,
};
this.stringWithPlaceholder = ...
};
stringWithPlaceholder: string;
...
};
Această variabilă este creată în constructor, dar nu este transmisă ca elemente de recuzită. Deoarece folosim Flow pentru verificarea de tip a elementelor de recuzită trecute în constructor, aceasta necesită totul în interiorul constructorului fi tip verificat. Este cunoscut că Flow necesită acest lucru, iar acest lucru se poate face prin specificarea tipului lor în blocul de clase.
În acest moment, accesoriile și statul sunt complete. Să vedem câteva exemple suplimentare rapide de verificare a tipului în cadrul acestei componente. * Consultați comentariile ESLint de închidere pentru orice erori raportate în acest moment.
Tipuri Return, Event și Node
togglePopover
nu ia niciun argument, deci poate fi văzut un exemplu simplu de specificare a niciunei valori de returnare:
togglePopover = (): void => {
...
};
keyboardOnlyTogglePopover
nu returnează nimic, dar are un singur parametru. Acesta este un eveniment, în special un eveniment de apăsare a tastelor. SyntheticKeyboardEvent
este folosit la fel de
React folosește propriul sistem de evenimente, deci este important să utilizați tipurile SyntheticEvent în loc de tipurile DOM precum Event, KeyboardEvent și MouseEvent.
keyboardOnlyTogglePopover = (e: SyntheticKeyboardEvent<>): void => {
...
};
Popover
este definit în render()
și returnează o instanță a ListPopover
Componentă funcțională pe care am analizat-o anterior. Putem specifica tipul său de returnare ca React Node
. Cu toate acestea, pentru a putea face acest lucru, trebuie mai întâi să-l importăm, așa cum este nu este accesibil în mod implicit. Există mai multe modalități de a-l importa, dintre care unul indicat mai jos:
import React, { Component } from 'react';
import type { Node } from 'react';
...
const Popover: Node = (
<ListPopover
onClose={this.togglePopover}
isOpen={this.state.popoverIsOpen}
strings={this.props.strings}
target={() => document.getElementById('ListPopoverLink')}
/>
);
Verificarea tipului componentelor React importate
Când tipurile Prop au fost declarate într-o componentă, ele pot fi folosite atunci când se utilizează componenta respectivă într-o altă componentă. Cu toate acestea, dacă utilizați un index.js
pentru a exporta prima componentă, apoi fluxul, // @flow
va trebui adăugat la index.
// @flow
import ListPopover from './ListPopover';
export default ListPopover;
Marcarea elementelor de recuzită ca opțional
Un accesoriu poate fi marcat ca opțional folosind prop?: type
sintaxă, de exemplu:
type Props = {
strings: { [string_key: string]: string },
hideBannerClick?: Function,
};
Acest lucru este acceptat, dar nu mai este recomandat de Flow. În schimb, toate accesoriile ar trebui lăsate după cum este necesar, cu nr ?
, chiar dacă este opțional, ca Flow detectează automat default Propune și marchează recuzita cu o valoare implicită ca opțională la nivel intern.
În secțiunea de mai jos putem vedea cum marcarea manuală a accesoriilor ca opțional poate provoca conflicte cu alte instrumente în unele cazuri.
Extensii ESLint, accesorii implicite și soluții de eroare de validare a accesoriilor
Două adăugiri sunt făcute la .eslintrc
. Pentru acest proiect, puteți accepta pur și simplu utilizarea lor sau puteți citi detaliile de mai jos dacă vedeți oricare dintre cele trei erori:
x missing in props validation
error defaultProp "x" defined for isRequired propType
Cannot get strings.xxx because property xxx is missing in undefined
Regulile adăugate, cu raționament, sunt:
"react/default-props-match-prop-types": [
"error", { "allowRequiredDefaults": true }
]
Atunci când se utilizează obiecte ca hărți (în acest caz pentru prop-ul „șiruri”) a missing in props validation
apare o eroare. Aceasta este un gândac și așa este în mod explicit ignorat Aici.
"react/default-props-match-prop-types": [ "error", { "allowRequiredDefaults": true }]
Când folosiți obiecte ca hărți, intră în joc complexități între ESLint, flux și tipuri de prop.
strings
este un element necesar, transmis ca obiect al șirurilor. Tipul de flux verifică dacă pentru fiecare intrare din obiect cheia șirului este un șir, iar valoarea este un șir. Acest lucru este mult mai ușor de întreținut decât să fie nevoie să enumerați tipul de accesoriu al fiecărei chei specifice.
Dacă recuzita este marcată după cum este necesar în Flow, atunci ESLint ar erora afirmând: error defaultProp "strings" defined for isRequired propType
.
Dacă recuzita este marcată manual ca opțională, atunci Flow va erora cu Cannot get strings.xxx because property xxx is missing in undefined [1]
.
Aceasta este cunoscut și se datorează invalidarea rafinamentului deoarece JSX poate transforma apelurile de metodă, Flow nu poate fi sigur că xxx nu a fost redefinit.
Acest lucru ne lasă cu remedierea erorii ESLint. Regulile de mai sus permit definirea DefaultProps în timp ce tipul Flow este nu marcat ca opțional. Flow va înțelege acest lucru și îl va converti în opțional. ESLint este marcat cu "allowRequiredDefaults": true
, ceea ce înseamnă că, deși ESLint vede recuzita ca fiind necesară, nu va greși.
Gânduri finale
Odată depășit obstacolul inițial de instalare, Flow este destul de simplu de utilizat. Abilitatea de a-l adăuga progresiv ajută cu siguranță, mai degrabă decât să fie nevoie să refactorizați un întreg proiect dintr-o singură dată.
Sperăm că instrucțiunile de configurare și exemplele de aici se dovedesc utile dacă doriți să încercați Flow out.
Mulțumesc că ai citit?
Vă puteți bucura, de asemenea:
#Cum #adaugă #în #mod #incremental #Flow #întro #aplicație #existentă #React
Cum se adaugă în mod incremental Flow într-o aplicație existentă React