tiknil / react-native-style-guide

Tiknil's style guide & coding conventions for React Native projects

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

react-native-style-guide

Guida di riferimento per i progetti React Native gestiti da Tiknil e i suoi collaboratori.

L'obiettivo è darsi delle best practices sulla stesura del codice per agevolare il lavoro in team e velocizzare la comprensione del codice.

Riferimenti

Alcuni contenuti di questa guida sono ispirati dai seguenti interessanti articoli di settore:

  • AirBnb JavaScript Style Guide: ottima linea guida per la stesura del codice JavaScript creata da AirBnb nel periodo in cui ha investito molto su React Native.

Sommario

Prerequisiti

Per realizzare un'applicazione in React Native è (ovviamente) un prerequisito fondamentale la conoscenza di JavaScript.

Boilerplate

Impostando il progetto a partire dal boilerplate tiknil si ottiene un progetto già configurato secondo le convenzioni Tiknil, con i moduli principali già installati e pronto per lo sviluppo 🚀

Stile della sintassi

In JavaScript i ; sono opzionali e noi preferiamo non utilizzarli perché il codice rimane più pulito e in molti casi ne agevola il mantenimento.
Ad esempio in questo caso:

// 👎
promise()
	.then(thenCallback)
	.catch(catchCallback);
	
// 👍
promise()
	.then(thenCallback)
	.catch(catchCallback)

Infatti se devo aggiungere il metodo finally mi basta aggiungere una riga senza dover cancellare (o spostare) il ;.

promise()
	.then(thenCallback)
	.catch(catchCallback)
	.finally(finallyCallback)

È comunque permesso inserire un ; in qualsiasi caso in cui la sintassi non fosse particolarmente comprensibile.

Faremo, inoltre, utilizzo di ECMAScript 6+ (ES 2015+) per utilizzare vari improvements che permettono uno stile di programmazione più evoluto:

Let e Const

Evitare di dichiarare variabili tramite var e usare invece const e let a seconda che siano costanti o variabili.
Essi infatti sono block-scoped, al contrario di var che è global-scoped con ovvi vantaggi al fine di evitare errori di riassegnazione di variabili fuori dallo scope corrente.

Destructuring

Quando è necessario accedere a proprietà multiple di un oggetto è utile utilizzare l'operazione di destructuring:

// 👎
function getFullName(user) {
  const firstName = user.firstName
  const lastName = user.lastName

  return `${firstName} ${lastName}`
}
	
// 👍
function getFullName(user) {
  const { firstName, lastName } = user
  return `${firstName} ${lastName}`
}

// 👍: è addirittura possibile destrutturare direttamente nel parametro
function getFullName({ firstName, lastName }) {
  return `${firstName} ${lastName}`
}

È possibile applicare il destructuring anche agli array. Nota: l'ordine è importante!

const arr = [1, 2, 3, 4]

// 👎
const first = arr[0]
const second = arr[1]

// 👍
const [first, second] = arr

Moduli

Utilizzare sempre import / export per gestire importazione ed esportazione dei moduli.

// 👎
const ReactNativeStyleGuide = require('./ReactNativeStyleGuide');
module.exports = ReactNativeStyleGuide.es6;

// 👍
import ReactNativeStyleGuide from './ReactNativeStyleGuide';
export default ReactNativeStyleGuide.es6;

// 👍: è possibile destrutturare direttamente nell'import
import { es6 } from './ReactNativeStyleGuide';
export default es6;

Unica eccezione è per gli inline requires volti ad ottimizzare il tempo di caricamento dell'app tramite RAM bundles

Classi

Finalmente anche in JavaScript è possibile utilizzare la sintassi a classi, molto più leggibile del vecchio sistema a prototypes.

// 👎
function Queue(contents = []) {
  this.queue = [...contents];
}
Queue.prototype.pop = function () {
  const value = this.queue[0];
  this.queue.splice(0, 1);
  return value;
};

// 👍
class Queue {
  constructor(contents = []) {
    this.queue = [...contents];
  }
  pop = () => {
    const value = this.queue[0];
    this.queue.splice(0, 1);
    return value;
  }
}

Parametri di default

Ai parametri dei metodi è possibile assegnare un valore di default nel caso il metodo venga invocato senza quel parametro.

// 👎: molto male; mai mutare il contenuto dei parametri
function handleThings(opts) {
  opts = opts || {};
  // ...
}

// 👍
function handleThings(opts = {}) {
  // ...
}

Template strings

Quando vanno costruite programmaticamente delle stringhe è meglio utilizzare il template piuttosto che la concatenazione perché offre una sintassi più chiara e concisa.

// 👎
function sayHi(name) {
  return 'How are you, ' + name + '?';
}

// 👍
function sayHi(name) {
  return `How are you, ${name}?`;
}

Arrow functions

Nel caso sia necessario utilizzare funzioni anonime (ad esempio in caso di callback inline) usiamo l'arrow notation.

// 👎
[1, 2, 3].map(function (x) {
  const y = x + 1
  return x * y
})

// 👍
[1, 2, 3].map((x) => {
  const y = x + 1
  return x * y
})

Vedi anche la sezione this

this

Oltre che per le funzioni anonime, le arrow functions sono molto comode per manipolare l'oggetto this nelle nostre classi. Difatti in Javascript l'oggetto this si comporta in maniera inaspettata rispetto a linguaggi più rigidi. Su MDN è disponibile una guida completa sull'utilizzo del this in Javascript. Per quanto riguarda lo scopo di questa guida, è sufficiente la seguente distinzione (semplificata):

  • L'oggetto this all'interno di una funzione standard rappresenta il contesto da cui la funzione è stata chiamata
  • L'oggetto this all'interno di un'arrow function rappresenta il contesto in cui la funzione è stata chiamata

Supponiamo di avere il sguente codice:

class Test {
  x = 2

  getX() {
    return this.x
  }

  // Stessa funzione ma implementata come arrow function
  arrowGetX = () => this.x
}

class CallbackClass {
  x = 'pippo'
  callback = null

  constructor(cb) {
    this.callback = cb
  }

  callFunction() {
    return this.callback()
  }
}

const t = new Test()
const cb = new CallbackClass(t.getX)
console.log(cb.callFunction()) // Ritorna 'pippo', perchè il this si riferisce al contesto da cui è stata chiamata, ovvero la classe CallbackClass
const arrowCb = new CallbackClass(t.arrowGetX)
console.log(arrowCb.callFunction()) // Ritorna x, perchè il this si riferisce al contesto in cui è stata definita

In generale, il comportamento desiderato è quello delle arrow function e quindi conviene usarle sempre per implementare i metodi delle nostre classi. Unica eccezione vale per i metodi riferiti al lifecycle della classe (constructor, componentDidMount, componentWillUnmount, ...) che non possono essere implementati con arrow function.

ESLint

ESLint è un tool che monitora lo stile in cui il codice JS è stato scritto, segnalando (e fixando automaticamente) inconsistenze di stile o sezioni di codice poco leggibile. Nel boilerplate tiknil è presente un file di configurazione (.eslintrc.js) che implementa le regole di sintassi elencate di seguito e le best practices consigliate da react native. Configurando l'IDE per utilizzare ESLint, ci si assicura che il codice scritto sia consistente con gli standard e facilmente leggibile.

🔔 TIP: puoi configurare l'IDE per fixare il file aperto con una semplice combinazione di tasti

Altro

Qui è possibile vedere un recap di tutti gli improvements di ECMAScript 6+.

IDE

Per lo sviluppo in react native sono stati selezionati 2 possibili strumenti, un editor e un IDE completo:

  • Visual Studio Code è stato identificato come il miglior editor in quanto rapido e molto completo. Da preferire rispetto ad altri editor quali Atom o Sublime Text
  • WebStorm è un IDE e di conseguenza molto più pesante rispetto a Visual Studio Code. Tuttavia, presenta vari vantaggi quali una miglior integrazione con Flow, un miglior supporto all'autocomplete e al refactoring dei file (es. spostando un file vengono corretti tutti gli import di quel file nel progetto). PHPStorm è di fatto un estensione di WebStorm con miglior supporto a PHP ed è interscambiabile.

Sia Visual Studio Code che WebStorm/PHPStorm possono essere configurati per supportare comodamente le tecnologie utilizzate (Flow e ESLint)

Tecnologie utilizzate

In un progetto React Native normalmente utilizziamo le seguenti tecnologie di supporto:

Tecnologia Ruolo Note
Yarn Dependency manager di Node Consigliato l'utilizzo di Yarn al posto di npm in quanto più rapido nel download delle dipendenze e con un miglior supporto al file di lock.
Si può installare tramite npm con il comando npm install -g yarn
Flow Static type checker Permette di introdurre un minimo di type-safety in JavaScript tramite analisi statica del codice.
Gli IDE indicati supportano un plugin di flow che permette di vedere inconsistenze di flow come errori e warnings all'interno del codice. Non ha alcun effetto a runtime.
Moment Gestore date e orari Libreria JS per parsing, validazione, manipolazione e visualizzazione di date e orari.
React Native Framework Mobile Framework crossplatform con output mobile nativo basato su React JS.
Redux State container Libreria JS che agevola l'applicazione di un pattern di sviluppo che permette di realizzare codice più testabile e consistente su diverse piattaforme.
Immutable Dati immutabili Libreria JS che permette di generare collezioni di dati immutabili.
Particolarmente utile in combinazione con lo state di React perché permette di evitare inutili refresh di componenti quando non necessario.

Struttura del progetto

La struttura del progetto è organizzata come segue:

  • android/ Contiene il progetto android e tutto il codice android nativo. Cartella da aprire con Android Studio

  • ios/ Contiene il progetto ios, il codice nativo e il podfile per l'installazione delle dipendenze. Da aprire con Xcode

  • flow-typed/ Contiene file javascript che vengono utilizzati da flow per rilevare dei Tipi utilizzabili all'interno del codice js senza necessità di import

  • src/ Contiene tutto il codice javascript:

    • assets/ contiene gli asset statici usati dal codice javascript (immagini, fonts, ecc)

    • components/ contiene component React riutilizzabili sul codice. Idealmente dovrebbero essere dump components, che si limitano a comporre il compomente grafico sulla base delle proprietà ricevute e propagano al padre eventi e interazioni dell'utente.

      • template.js questo file contiene il boilerplate di un componente tipico, da usare come punto di partenza per gli altri componenti
    • ducks/ Implementazioni dei reducer e delle azioni redux seguendo lo standard dei ducks: https://github.com/erikras/ducks-modular-redux

    • networking/ Implementazione delle chiamate HTTP

    • screens/

      • [screen-name]

        • index.js Mapping sullo state Redux e dispatch delle azioni necessarie alla schermata
        • component.js Implementazione del componente stesso
        • components/ (opzionale) componenti usati solo da questa schermata
      • setup.js Definizione della navigazione tra le schermate (es. creazione di navigators in caso di utilizzo di react-navigation)

    • translations/ Contiene i file json delle stringhe localizzate su varie lingue (es. it.json, en.json)

    • utils/ funzioni javascript utilizzate in più punti dell'app. In questa cartella NON vanno inseriti componenti react.

    • i18n.js file che esporta l'oggetto da utilizzare per ottenere le stringhe localizzate

    • index.js Entry point dell'app: inizializza redux ed effettua il render del root component

    • redux-setup.js Inizializzazione di redux, chiamato da src/index.js

    • styles.js Esporta un oggetto contente lo stile grafico (font, margini, colori..) dell'app

React Native

coming soon

Redux

coming soon

Immutable

coming soon

Navigation

coming soon

Persistenza dei dati

coming soon

Test

coming soon

About

Tiknil's style guide & coding conventions for React Native projects

License:MIT License