• 30 heures
  • Moyenne

Ce cours est visible gratuitement en ligne.

course.header.alt.is_video

course.header.alt.is_certifying

J'ai tout compris !

Mis à jour le 09/09/2020

Utilisez les Props

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Il est temps d'avancer sur notre application. Dans ce chapitre, nous allons créer une liste de données avec des films. Cela va me permettre de vous présenter un nouveau concept : les Props. Un nom qui ne rassure pas, je vous l'accorde, mais, une fois de plus, il n'y a rien de compliqué, vous verrez.

On est parti un peu dans tous les sens dans le précédent chapitre, lorsque l'on a manipulé les styles. Afin de partir tous sur la même base, assurez-vous d'avoir le même projet que moi actuellement :

// App.js
import React from 'react'
import Search from './Components/Search'
export default class App extends React.Component {
render() {
return (
<Search/>
)
}
}
// Components/Search.js
import React from 'react'
import { StyleSheet, View, TextInput, Button, Text } from 'react-native'
class Search extends React.Component {
render() {
return (
<View style={styles.main_container}>
<TextInput style={styles.textinput} placeholder='Titre du film'/>
<Button title='Rechercher' onPress={() => {}}/>
</View>
)
}
}
const styles = StyleSheet.create({
main_container: {
flex: 1,
marginTop: 20
},
textinput: {
marginLeft: 5,
marginRight: 5,
height: 50,
borderColor: '#000000',
borderWidth: 1,
paddingLeft: 5
}
})
export default Search

C'est bon ? Alors on y va et on commence par créer notre liste de données avec des films.

Liste de données

Première question à se poser :

Est-ce qu'il existe un component React Native permettant de créer une liste de données ?

On se réfère à la documentation de React Native et on voit un certain component FlatList qui permet justement d'afficher une liste de données.

Vous connaissez la chanson, on commence par importer le component React Native dans notre fichier Search.js :

// Components/Search.js
import { ..., FlatList } from 'react-native'

Puis on ajoute une FlatList dans notre component custom Search :

// Components/Search.js
render() {
return (
<View style={styles.main_container}>
<TextInput style={styles.textinput} placeholder='Titre du film'/>
<Button title='Rechercher' onPress={() => {}}/>
{/* Ici j'ai simplement repris l'exemple sur la documentation de la FlatList */}
<FlatList
data={[{key: 'a'}, {key: 'b'}]}
renderItem={({item}) => <Text>{item.key}</Text>}
/>
</View>
)
}

Une FlatList doit obligatoirement implémenter deux propriétés :

  • data : qui correspond aux données affichées dans la liste. Ici, on renseignera nos films ;

  • renderItem : qui correspond au rendu des données de la liste. Ici, on définira un template pour afficher nos films.

Regardez à présent du côté de votre device. Vous devriez voir ceci :

Notre première liste de données : FlatList
Notre première liste de données : FlatList

C'est très très... moche. :D Mais cela fait le boulot, pour l'instant.

Vous remarquez que l'on n'a pas défini de style  height  ou de valeur  flex  sur notre FlatList ? Et pourtant, elle s'affiche ?

Souvenez-vous du chapitre précédent. Lorsque l'on ne définit pas de style  height  ou  flex  sur un component, sa taille dépend de celle de ses components enfants. Ici, les components enfants sont nos  renderItems avec des Text.

Oui, mais attends, nos  renderItems Text, là, ils n'ont pas non plus de taille définie. Tu n'essaies pas un peu de me la faire à l'envers, là ?

Bien vu. ;) En fait, les components Text sont un cas un peu particulier. Il y a un troisième paramètre qui entre en jeu pour définir sa taille : c'est la taille de la police (  fontSize  ). Si vous ne définissez pas de  height  ni de  flex >= à 1 , votre Text va prendre la taille définie par le style  fontSize . En React Native, les Text ont une  fontSize  par défaut qui vaut 14. C'est pour cela que vos Text sont visibles sans style  height  ou  flex .

C'est pareil pour tous les components React Native qui ont un rapport avec du texte : Text, TextInput et Button.

À présent que notre liste de données est prête, il est temps de la remplir avec de véritables informations de films.

Remplissez votre liste de films

 Afin d'afficher des données un peu cohérentes, je vous ai préparé un fichier Javascript avec des données de films. Je vous invite à créer un dossier Helpers à la racine de votre projet et à y ajouter le fichier filmsData.js : 

// Helpers/filmsData.js
export default data = [
{
id:181808,
vote_average:7.2,
title:"Star Wars VIII - Les derniers Jedi",
poster_path:"",
original_title:"Star Wars: The Last Jedi",
overview:"Nouvel épisode de la saga. Les héros du Réveil de la force rejoignent les figures légendaires de la galaxie dans une aventure épique qui révèle des secrets ancestraux sur la Force et entraîne de choquantes révélations sur le passé…",
release_date:"2017-12-13"
},
{
id:181809,
vote_average:8.1,
title:"La Guerre des étoiles",
poster_path:"",
original_title:"Star Wars",
overview:"Il y a bien longtemps, dans une galaxie très lointaine... La guerre civile fait rage entre l'Empire galactique et l'Alliance rebelle. Capturée par les troupes de choc de l'Empereur menées par le sombre et impitoyable Dark Vador, la princesse Leia Organa dissimule les plans de l’Étoile Noire, une station spatiale invulnérable, à son droïde R2-D2 avec pour mission de les remettre au Jedi Obi-Wan Kenobi. Accompagné de son fidèle compagnon, le droïde de protocole C-3PO, R2-D2 s'échoue sur la planète Tatooine et termine sa quête chez le jeune Luke Skywalker. Rêvant de devenir pilote mais confiné aux travaux de la ferme, ce dernier se lance à la recherche de ce mystérieux Obi-Wan Kenobi, devenu ermite au cœur des montagnes désertiques de Tatooine...",
release_date:"1977-05-25"
}
]

 À présent, dans le fichier Javascript Search.js, on va importer ces données : 

// Components/Search.js
import films from '../Helpers/filmsData'

 Et on va afficher le titre de nos films dans la  FlatList : 

// Components/Search.js
<FlatList
data={films}
renderItem={({item}) => <Text>{item.title}</Text>}
/>

Un petit coup d’œil, côté application :

Que la force soit avec vous !
Que la force soit avec vous !

En React Native, lorsque vous créez une  FlatList , vous devez identifier chaque item de manière unique. Pour cela, il faut définir une propriété key sur nos items. Tout à l'heure, l'application n'a rien dit puisque l'on avait défini une key sur nos valeurs (au lieu des items), ce qui fonctionne aussi :  data={[{key: 'a'}, {key: 'b'}]}  .

Nous, nous allons faire les choses bien en utilisant une propriété des  FlatList , spécialement créée pour définir une key sur les items : il s'agit de  keyExtractor .

<FlatList
data={films}
keyExtractor={(item) => item.id.toString()}
renderItem={({item}) => <Text>{item.title}</Text>}
/>

Dans le  keyExtractor, vous devez spécifier la propriété de votre item qui va servir de key. Assurez-vous que votre key soit toujours unique. Normalement, ici, avec un identifiant, on ne prend pas trop de risque : les identifiants sont faits pour être uniques. :) 

Si vous retournez côté application, le warning a disparu. :ninja:

 On a renseigné une key sur nos items, OK, mais pourquoi doit-on faire cela ?

Les listes de données ont un fonctionnement un peu complexe. Lorsque vous défilez dans une liste de données, des items sont ajoutés à votre liste. Les items qui ne sont plus visibles à l'écran sont supprimés afin de ne pas surcharger votre application.

Lorsque vous définissez une key, React peut rapidement identifier de manière unique un item et faire l'action adéquate : ajout, suppression, voire modification. C'est un peu le même fonctionnement que  StyleSheet, à la différence qu'ici, nous devons nous-mêmes définir l'identifiant.

Items customs pour notre liste de données

Cela vous dit de customiser un peu nos items ? Afficher le titre d'un film, c'est bien, mais on peut faire mieux. Dans cette sous-partie, on va manipuler les styles à fond. C'est l'occasion de faire un rappel et surtout de vous perfectionner.

Lorsque l'on crée des items customs graphiquement complexes, on a pour habitude de créer un nouveau component custom. Et qui dit nouveau component custom dit nouveau fichier Javascript. Alors allez-y et créez un nouveau fichier FilmItem.js dans le dossier Components.

Créez la structure de notre component custom, essayez de le faire vous-même pour vous entraîner :

// Components/FilmItem.js
import React from 'react'
import { StyleSheet } from 'react-native'
class FilmItem extends React.Component {
render() {
return (
)
}
}
const styles = StyleSheet.create({
})

On va poser la base du rendu de notre component custom FilmItem pour avoir le même rendu que tout à l'heure :

// Components/FilmItem.js
import React from 'react'
import { StyleSheet, View, Text } from 'react-native'
class FilmItem extends React.Component {
render() {
return (
<View style={styles.main_container}>
<Text style={styles.title_text}>Titre du film</Text>
</View>
)
}
}
const styles = StyleSheet.create({
main_container: {
height: 190
},
title_text: {
}
})
export default FilmItem

 Notre nouvel item FilmItem est prêt, on peut l'utiliser dans notre liste de données. Dans le fichier Javascript Search.js

// Components/Search.js
...
import FilmItem from './FilmItem'
...
<FlatList
data={films}
keyExtractor={(item) => item.id.toString()}
renderItem={({item}) => <FilmItem/>}
/>

On obtient :

Template de départ pour FilmItem
Template de départ pour FilmItem

À présent que je vous ai donné le squelette pour démarrer votre item FilmItem, je veux que vous réalisiez un item comme celui-ci :

Item custom final à réaliser côté Application
Item custom final à réaliser côté application

Wow, tu passes d'un squelette avec un texte à ça ? Tu ne nous surestimes pas un peu, là ?

Non, croyez-moi, vous en êtes parfaitement capable, vous avez tous les éléments pour le faire. Bon, excepté le fait que je ne vous ai pas encore montré comment récupérer les informations du film et comment les donner au component FilmItem. Donc pour l'instant, on va se contenter de ceci, c'est déjà bien : ;)

Item custom à réaliser dans un premier temps
Item custom à réaliser dans un premier temps

Je vous ai préparé un petit graphe pour vous montrer la démarche à suivre lorsque l'on crée un nouveau component complexe (ici, notre item FilmItem). Vous devez décomposer votre component en vues imbriquées les unes dans les autres afin de gérer les différents alignements d'éléments :

Décomposer un component custom complexe
Décomposer un component custom complexe

Avant de regarder la solution, essayez de le faire par vous-même. Appuyez-vous sur ce cours et la documentation React Native. Vous apprendrez à manipuler les différents styles et surtout à bien découper votre component pour gérer tous les alignements d'éléments.

Quand vous pensez avoir trouvé, vous pouvez vérifier avec la solution :

// Components/FilmItem.js
import React from 'react'
import { StyleSheet, View, Text, Image } from 'react-native'
class FilmItem extends React.Component {
render() {
return (
<View style={styles.main_container}>
<Image
style={styles.image}
source={{uri: "image"}}
/>
<View style={styles.content_container}>
<View style={styles.header_container}>
<Text style={styles.title_text}>Titre du film</Text>
<Text style={styles.vote_text}>Vote</Text>
</View>
<View style={styles.description_container}>
<Text style={styles.description_text} numberOfLines={6}>Description</Text>
{/* La propriété numberOfLines permet de couper un texte si celui-ci est trop long, il suffit de définir un nombre maximum de ligne */}
</View>
<View style={styles.date_container}>
<Text style={styles.date_text}>Sorti le 00/00/0000</Text>
</View>
</View>
</View>
)
}
}
const styles = StyleSheet.create({
main_container: {
height: 190,
flexDirection: 'row'
},
image: {
width: 120,
height: 180,
margin: 5,
backgroundColor: 'gray'
},
content_container: {
flex: 1,
margin: 5
},
header_container: {
flex: 3,
flexDirection: 'row'
},
title_text: {
fontWeight: 'bold',
fontSize: 20,
flex: 1,
flexWrap: 'wrap',
paddingRight: 5
},
vote_text: {
fontWeight: 'bold',
fontSize: 26,
color: '#666666'
},
description_container: {
flex: 7
},
description_text: {
fontStyle: 'italic',
color: '#666666'
},
date_container: {
flex: 1
},
date_text: {
textAlign: 'right',
fontSize: 14
}
})
export default FilmItem

Normalement, vous devriez retrouver uniquement des styles et components que l'on a vus ensemble. Rien de nouveau, si ce n'est :

  • le style  flexWrap: 'wrap'  sur le titre du film qui permet à notre texte de passer à la ligne si celui-ci est trop long ;

  • la propriété  numberOfLines={6}  sur un Text qui, vous l'aurez compris, définit un nombre maximum de lignes pour un texte. Si le texte fait plus de 6 lignes, votre texte est coupé et l'application affiche "..." à la fin du texte ;

  • le component Image de React Native qui possède une propriété  source  pour définir l'image à afficher.

Notre component custom FilmItem est construit, il répond à nos attentes, son template est correct, ses styles bien définis. Il ne manque plus qu'à remplacer nos données "Titre du film", "Description", etc., par de véritables données. C'est ici que vont intervenir les props.

Props

En voyant le titre de cette sous-partie, vous vous êtes peut-être dit :

OK, on arrive au niveau des props, le nouveau concept du chapitre, je ferais peut-être mieux d'aller prendre un café et de revenir avec l'esprit apaisé. 

Et bien, ce n'était pas nécessaire. ^^ Vous savez déjà ce qu'est une prop, c'est juste le mot "prop" que vous ne connaissez pas.

Depuis le début de ce cours, on utilise les props. Par exemple, quand on fait :

<Text style={styles.description_text} numberOfLines={6}>Description</Text>

On a utilisé deux props.  style  est une prop,  numberOfLines  est une autre prop. En fait, en React Native, on appelle tout simplement les propriétés d'un component des props

OK, donc non seulement, tu me fais boire du café pour rien, mais, en plus, tu crées une sous-partie juste pour nous parler de son nom spécifique sur React Native ?

Non, rassurez-vous, j'ai d'autres choses à vous apprendre sur les props des components.

Pour bien comprendre le fonctionnement des props en React Native, il faut imaginer vos components custom ou React Native comme des classes. Dans l'exemple juste au-dessus, c'est comme si on avait une classe Text :

class Text {
var style;
var numberOfLines;
}

Et que l'on avait fait ceci :

var text = new Text();
text.style = styles.description_text;
text.numberOfLines = 6;

Bien sûr, mon code ci-dessus n'a aucun sens, mais vous comprenez l'idée. :D Chaque component possède ses props qui correspondent, en soi, à des variables que l'on peut définir.

Les components React Native possèdent leurs props. On en a déjà découvert certaines :  style  ,  numberOfLines  ,  height  ,  padding  ,  onPress, etc. Vous pouvez retrouver la liste des props disponibles sur chaque component sur la documentation React Native. Je vous mets, par exemple, le lien vers les props du component Text

Les props deviennent vraiment intéressantes parce que l'on peut créer ses propres props et les ajouter à nos components customs. Par exemple, on peut ajouter une prop name  sur un component custom Person, une prop town  sur un component custom Address ou encore une prop film  sur un component custom FilmItem. Vous voyez où je veux en venir ? :)

Ajoutez des props à nos components custom

Si on reprend notre application et notre component custom FilmItem, qu'a-t-on besoin de faire exactement ?

On souhaite faire passer le film et ses informations à notre component custom FilmItem. Et bien, pour cela, on va utiliser les props en créant notre propre prop (c'est dur à dire ^^) sur le component custom FilmItem.

Dans le component custom Search où on initialise nos items FilmItem, ajoutez notre propre prop film  , comme ceci : 

// Components/Search.js
<FlatList
//...
renderItem={({item}) => <FilmItem film={item}/>}
/>

Grâce à l'ajout de cette prop, on fait passer l'item en cours (un film) aux components custom FilmItem de notre FlatList.

Et on s'arrête là pour l'ajout de props, cela fonctionne comme cela. Vous pouvez passer tout type d'information via les props : entier, booléen, chaîne de caractères, objet, tableau et même fonction. On aura l'occasion d'y revenir un peu plus tard dans ce cours.

Récupérez les props

Maintenant que notre component custom FilmItem possède une prop film  qui contient le film en cours, il faut qu'on la récupère.

Où se trouve notre prop film, à votre avis ?

Arrêtez de réfléchir, vous ne pouvez pas le deviner, par contre vous pouvez le déduire. Je ne vous en ai pas encore parlé, mais on peut utiliser des logs dans nos applications pour nous aider à débuguer. Là, c'est du Javascript pur et dur. On va simplement utiliser la fonction  console.log et afficher les props de notre component custom FilmItem  this.props . 

// Components/FilmItem.js
class FilmItem extends React.Component {
render() {
console.log(this.props)
return (
...
)
}
}

Vous devez vous demander où s'affichent nos logs. C'est tout simplement dans le terminal où vous avez lancé la commande :

$ npm start 

Au milieu des nombreux :

$ Finished building JavaScript bundle in XXXX ms

Lancez l'application, si ce n'est pas déjà fait. Vous devriez voir apparaître :

Logs this.props du component FilmItem
Logs this.props du component FilmItem

Déjà, première chose,  this.props  est un objet. Ensuite, dans l'objet  this.props, on retrouve notre objet film avec toutes les informations du film en cours. Si vous me suivez jusque là, vous devriez avoir une petite idée de comment récupérer notre film ici.

Tout simplement en faisant  this.props.film .

Affichez les informations du film

Dans notre component custom FilmItem, on va récupérer le film et remplacer nos textes par défaut par les informations du film :

// Components/FilmItem.js
render() {
const film = this.props.film
return (
<View style={styles.main_container}>
<Image
style={styles.image}
source={{uri: "image"}}
/>
<View style={styles.content_container}>
<View style={styles.header_container}>
<Text style={styles.title_text}>{film.title}</Text>
<Text style={styles.vote_text}>{film.vote_average}</Text>
</View>
<View style={styles.description_container}>
<Text style={styles.description_text} numberOfLines={6}>{film.overview}</Text>
</View>
<View style={styles.date_container}>
<Text style={styles.date_text}>Sorti le {film.release_date}</Text>
</View>
</View>
</View>
)
}

Et côté application :

Ajout des informations du film sur notre component custom FilmItem
Ajout des informations du film sur notre component custom FilmItem

Génial ! C'est exactement ce que l'on voulait. Même le texte de notre description s'arrête bien à 6 lignes, tout fonctionne. :soleil:

Vous savez à présent utiliser les props pour faire passer des informations d'un component à un autre et comment les récupérer. C'est extrêmement utile et vous verrez qu'en React Native, on s'en sert tout le temps. 

Nous avons également vu comment utiliser les logs pour débuguer notre application. Cela nous sera énormément utile dans la suite du cours et pour vos futurs projets. Vous pourrez décrypter chaque comportement de votre application, connaître le contenu de vos objets, etc. Ce type de débugage reste très basique, mais il est suffisant pour débuguer 90 % de nos anomalies. Pour les 10 % restants, on devra pousser un peu plus loin, avec de nouveaux outils que je vous présenterai dans la dernière partie de ce cours.

On arrive à afficher des films, c'est plutôt bien. Mais on n'en affiche que 2 et ce sont toujours les mêmes. Que dites-vous d'utiliser une véritable API spécialisée dans le cinéma pour récupérer autant de films que l'on souhaite ? Et bien, c'est ce que l'on va faire dans le prochain chapitre avec l'API The Movie Database.

Exemple de certificat de réussite
Exemple de certificat de réussite