Analizziamo la struttura del progetto3 (applicazione dimostrativa creata nei precedenti post12 ).
Il progetto progetto3 è stato ottenuto (dalla rete Internet) con questo comando:
$ nvm use node $ npx react-native init progetto3
- La scelta del nome progetto3 diventa permanente (il nome del progetto è molto difficile da cambiare)
- Prima di scegliere il nome del progetto è buona regola controllare se nel web esiste già una App con lo stesso nome, così come anche nei repository ufficiali delle applicazioni Android e iOS.
Nel febbraio 2023 le dimensioni del template suggerito si aggirano intorno ai 340 MB.
Analizzando le cartelle del progetto vuoto si può osservare approssimativamente questa struttura:
. + ── android + ── ios + ── node_modules ├─── App.js ├─── index.js └─── package.json
Chi lo desidera, può creare manualmente questa struttura, ma la forma della struttura dei progetti è sempre simile a questa. Per tale motivo, in termini tecnici, può essere chiamata “template“, oppure “boilerplate solution“, nel senso che tale soluzione si ripete spesso come un piatto pronto (il termine boilerplate deriva dalla consuetudine nelle tecniche di stampa).
In futuro vedremo altre soluzioni, altri template, altre boilerplate solution, ma per ora, vediamo alcune caratteristiche di questo semplice esempio. Cosa contegono questi file e queste cartelle create dal nulla?
- Le prime due cartelle (
android
eios
) non devono essere modificate direttamente (a parte casi particolari), ma contengono il codice generato automaticamente in fase di transcompilazione per le due piattaforme Android e iOS. - La terza cartella
node_modules
contiene i moduli, le librerie, Node.js installati localmente con npm package.json
è un file che contiene informazioni descrittive del progetto, metadati: il nome, la versione SDK Android, ecc.- ad esempio, questo codice:
"type": "module"
indica il tipo di moduli da utilizzare nel progetto (ad esempio, per importare librerie)
- ad esempio, questo codice:
index.js
è solo il punto di ingresso (entry point) dell’applicazione, e se si escludono gli import, esso è composto in sostanza da una riga (la riga 5 di questo esempio):
import {AppRegistry} from 'react-native'; import App from './App'; import {name as appName} from './app.json'; AppRegistry.registerComponent(appName, () => App);
Vale la pena soffermarsi sulla sintassi dell’ultima riga, dove è presente una arrow function. Le arrow function sono semplici funzioni in JavaScript. Possono essere funzioni anonime e possono essere definite “in linea” nel posto dove devono essere usate. In questo caso tali funzioni non sono invocate, ma sono passate come parametro ad altre funzioni.
App.js
contiene il vero e proprio codice sorgente. Ora vediamo le sue parti salienti (la numerazione delle righe potrebbe non corrispondere nel template):
const App = () => { return ( <SafeAreaView> <StatusBar> <ScrollView> <Header/> <View> <Section title="primo tentativo"> Questa è una prova </Section> </View> </ScrollView> </StatusBar> </SafeAreaView> ); }; export default App;
- App() è una funzione (una arrow function, ma potrebbe essere anche una classe)
- l’ultima riga esporta la funzione App per poterla usare dentro
index.js
(già visto) - La funzione App() restituisce un elemento che poi verrà rappresentato dentro l’applicazione dello smartphone
- questi elementi assomigliano esteticamente ai tag, ma hanno una iniziale Maiuscola. In effetti non sono tag HTML ma sono istanze di componenti3 (classi) di React
- La parte di rendering utilizza (per semplicità) il linguaggio JSX (tag maiusoli e altro)
- La parte di rendering è all’interno di
return
- La parte di rendering deve avere le parentesi tonde nel caso in cui sia necessario usare più di una sola riga
- JSX ha anche altre regole che saranno approfondite con altri esempi
- I vari componenti sono organizzati in un albero gerarchico
- I componenti senza figli si devono autochiudere (come Header)
- I vari componenti possono avere attributi (come i tag in HTML)
- Il component
<Section>
è un figlio sconosciuto e viene definito in un’altra parte del codice sorgente (di solito il suo codice è salvato in un diverso file sorgente di nomeSection.js
) - Tutti gli altri component genitori si possono ottenere da React Native con
import
Vediamo la parte che riguarda il component <Section>
(la numerazione delle righe potrebbe non corrispondere):
const Section = ({children, title}) => { return ( <View> <Text> {title} </Text> <Text> {children} </Text> </View> ); };
- Anche
<Section>
è un component definito come funzione dal programmatore (arrow function), ma poteva essere definito anche come una classe. La scelta dipende dallo stile del programmatore. - Il codice del component restituisce un elemento che verrà poi rappresentato dentro l’applicazione (rendered element)
- nella riga 1 “
title
” e “children
” sono proprietà (props
) che sono ricevute dal componentSection
e che vengono forniti dall’elemento genitore (in questo esempio:App
) - nella riga 4 una proprietà stringa viene visualizzata grazie alle parentesi graffe
{
}
. Nel linguaggio JSX, infatti, si possono racchiudere le stringhe in JavaScript dentro le semplici parentesi graffe {}. - la proprietà “
title
” è una semplice stringa, facile da capire, facile da passare (da App a Section) - la proprietà “
children
” viene passata in modo diverso. Permette di passare tutto il contenuto racchiuso da un component (un testo o un ulteriore component). Vedere il codice di App alla riga 9. - In questo caso il programmatore ha deciso di passare la proprietà “
Questa è una prova
” in modo diverso dalla proprietà “title
“, anche se non era necessario cambiare metodo. È stata solo una scelta dimostrativa. - A dire la verità questo cambiamento potrebbe complicare la comprensione dell’esempio.