Réact-Native : CRUD 1/2

Ce billet analyse un exemple de code "React-Native" pour gérer les opérations Create, Read et Delete sur une table d'une base de données stockée sur un serveur distant. Lire ICI la description de l'opération Update.

Les fonctions ReadRecords(), InsertRecord(), DeleteRecord() de ce code utilisent l'API fetch pour respectivement lire, insérer ou effacer des enregistrements de la table. L'URL, argument obligatoire de fetch  est un script php détaillé ICI.

Il peut être utile de (re) lire le billet sur l'utilisation de "useState" et celui sur la navigation pour comprendre l'appel des fonctions "Crud" et "UpdateCrud".

Le coeur :

La fonction Crud est appelée pour afficher la page d'accueil de notre navigation. Elle dispose donc des paramètres "navigation" et "route".

Elle dispose également des variables (internes) et de leur "setter":

  • data  pour mémoriser les données lues dans la BdD ;
  • studentName pour mémoriser le nom d'étudiant par exemple lors de sa saisie par l'utilisateur ;
  • course pour mémoriser le cours suivi par exemple lors de sa saisie par l'utilisateur ;
  • colore pour mémoriser la couleur d'une zone de saisie de données.

Par sa fonction "ReadRecords()", elle effectue une lecture de la Base de Données pour initialiser la variable data, puis par sa  fonction lire(), elle affiche une vue construite autour des enregistrements de la BdD   comme l'illustre la moitié supérieure de l'image ci-contre  et enfin par sa  fonction inscrire(), elle affiche une vue permettant la saisie d'un nouvel enregistrement comme le montre la 2nde moitié de l'image.

Cliquer pour agrandir l'image

La fonction ReadRecords()

Cette fonction utilise l'API fetch avec pour arguments :

  • l'URL du script de gestion de la BdD distante (voir ici sa description) dans la variable CrudAPIURL qui vaut "https://code.dhumbert.info/mycrud.php" ;
  • les réglages de l'URL dans le tableau
        {   
            method: 'POST',
            headers: Headers,
            body: JSON.stringify(Data),
        }
  •  

Comme indiqué dans le script "mycrud.php", pour une lecture de la  BdD,  le seul paramètre nécessaire à transmettre est "op". Il doit avoir "read" pour valeur, cela expliquele contenu de la variable "Data" qui constitue le corps (body) de la requête.

L'entête (headers) spécifie que le corps doit être émis au format JSON d'où l'utilisation de la fonction JSON.stringify sur "Data"

La requête est transmise en mode POST (pour que les paramètres ne figurent pas dans l'URL).

NB : si cette requête était transmise en mode GET, la forme de l'URL aurait été  "mycrud.php?op=read".

Les méthodes then et catch sont appliquées sur la réponse reçue.

D'après la ligne $response = array("Message"=>$msg, "Data"=>$data) du  fichier mycrud.php, les enregistrements de la BdD figurent dans l'entrée "Data" du tableau $response fourni comme résultat. C'est pourquoi, le setter setData() est appelé avec le paramètre response.Data pour mémoriser ces données dans la variable data de la fonction Crud() lorsqu'il y a des données à gérer.

La variable data est donc un tableau que l'on peut se représenter ainsi :

{
         {num :40, name :"Pierre", course :"informatique"}
         {num :48, name :"Marie", course :"informatique"}

}

La fonction Lire()

Le coeur de cette fonction est la fonction JS "map" . Map applique à chaque entrée du tableau data (initialisé par ReadRecords()), une fonction (anonyme) dont l'objectif est le rendu de la ligne constituée de :

  • une icône-bouton pour la mise à jour avec appel à la fonction Update() ayant comme paramètres num, name, course
  • une icône-bouton pour la suppression avec appel à la fonction Delete() de paramètre "num" ;
  • le nom name ;
  • le cours course suivi par l'étudiant inscrit dans la table.

Chaque ligne du tableau "data",  sur lequel s'applique map,  a 3 index : num, name et course, c'est pourquoi la fonction anonyme utilisée ici a 3 paramètres car on souhaite utiliser toutes les données de l'enregistrement.

Ces lignes sont dans un composant "ScrollView" pour permettre, le cas échéant,  à l'utilisateur de faire défiler les données affichées.

Pour n'afficher que la liste des noms des étudiants inscrits, la fonction anonyme utilisée serait :

function ( {name}) => (
                                <Text>{name}</Text>
                        )

d'où

data.map( {name}) => (
                                <Text>{name}</Text>
                        ))

La fonction Inscrire()

Cette fonction rends une vue composée de 2 zones de saisie de texte : "TextInput" et d'un bouton "Enregistrer" pour le traitement des saisies par l'appel de la fonction "InsertRecord()".

La propriété "onChangeText" de chaque "TextInput" fait appel au setter correspondant pour mémoriser la donnée saisie par l'utilisateur :

  • le setter "setStudentName"  mémorise le nom saisi dans la variable "studentName" ;
  • le setter "setCourse"  mémorise le nom du cours  saisi dans la variable "course" ;

La fonction InsertRecord()

Cette fonction utilise l'API fetch avec pour arguments :

  • l'URL du script de gestion de la BdD distante (voir ici sa description) : CrudAPIURL qui vaut "https://code.dhumbert.info/mycrud.php" :
  • le tableau
        {   
            method: 'POST',
            headers: Headers,
            body: JSON.stringify(Data),
        }

 

Pour une requête d'insertion dans la BdD,  les paramètres qui doivent être transmis sont :

  • "op"  avec "create" pour valeur  ;
  • "studentName" avec le nom de l'étudiant qui est contenu dans la variable studentName ;
  • "course" avec le nom du cours suivi  qui est contenu dans la variable course.

Les méthodes then et catch sont appliquées sur la réponse reçue. S'il n'y a pas eu d'erreur, les variables "studentName" et "course" sont réinitialisées.

La fonction Delete()

Cette fonction utilise l'API fetch avec pour arguments :

  • l' URL du script de gestion de la BdD distante (voir ici sa description) : CrudAPIURL qui vaut "https://code.dhumbert.info/mycrud.php" :
  • le tableau
        {   
            method: 'POST',
            headers: Headers,
            body: JSON.stringify(Data),
        }

Pour une requête de suppression dans la BdD,  les paramètres qui doivent être transmis sont :

  • "op"  avec "delete" pour valeur  ;
  • "num" avec le numéro de l'enregistrement à supprimer,  numéro reçu en paramètre de la fonction delete().

La fonction Update()

Cette fonction reçoit 3 paramètres ( le numéro de l'enregistrement, le nom de l'étudiant et le cours suivi).

Elle appelle la fonction anonyme

function () => {   
           navigation.navigate('UpdateCrud',{
                num: arg1,
                name: arg2,
                course: arg3,
            })
        };

qui appelle l'écran "UpdateCrud" en lui transmettant les 3 paramètres.

Cliquez sur le bouton pour copier le code dans le presse papier
import React, { useState } from "react";
import { StyleSheet,
        TextInput,
        Text,
        Button,
        TouchableHighlight,
        Image,
        ScrollView,
        Dimensions,
        View } from "react-native";

const screenHeight = Dimensions.get("screen").height;

const Crud =( {navigation, route} ) =>{
    const [ studentName, setStudentName ]=useState("");
    const [ course, setCourse ]=useState("");
    const [ data, setData ]=useState("");

    const [ colore, setColoreBorderInputText ]=useState("blue");

    const ReadRecords =() => {
            var CrudAPIURL="https://code.dhumbert.info/mycrud.php"; 
            var Headers={ 
                'Accept':'Application/JSON', 
                'Content-Type':'Application/JSON' 
                };     
        var Data={   
                   "op":"read" 
                    }; 

        fetch( 
             CrudAPIURL, 
                         {   
                          method: 'POST', 
                          headers: Headers, 
                          body: JSON.stringify(Data), 
                         })    
             .then( (response) => response.json()) 
             .then( (response) => 
                            {   
                              /*alert(response.Data[1].num);*/ 
                              var i = response.Data.length;   
                              if (i > 0) {  
                                   /*console.log(response.Data[i-1].num);*/ 
                                    setData ( response.Data );  
                                   } 
                                else { 
                                    setData("");
                                    console.error("Aucun enregistrement trouvé");  
                               }   
                          }) 
              .catch( (error) => 
                            {  
                               alert("error"+error);  
                               console.error(error); 
                            }) 
   
 }          
        
const Lire =() => {
         if (data==""){ 
             return( 
                <View> 
                    <Text>
                      Il n'y a aucun enregistrement dans la table
                    </Text>   
                 </View> 
             ) 
        }  
       else{
         return(
             <View  >
                 <View style={{width:"100%", backgroundColor:"coral",}}> 
                    <Text style={{ textAlign:"center", fontWeight :"bold",fontSize:20 }}>  
                       - Lecture de la table -
                    </Text>
             </View>
             <ScrollView  
                       /*horizontal ={true}    
                     pagingEnabled ={true}*/    
                     style={{ flexGrow:0, maxHeight: screenHeight / 3  }} 
                     persistentScrollbar={true}     
                     stickyHeaderComponent={"nom", "cours"}  
             >     
                    <View style={{width:"100%", backgroundColor:"cornsilk",}}>
                             <Text >  
                                </Text>
                             <Text > 
                                - faire défiler en glissant votre doigt  
                           </Text>      
                       <Text >       
                          - appuyez sur <Image  
                                         source={require('./ico/config.png')}  
                                         />    
                             pour mettre à jour l'enregistrement ...     
                        </Text>      
                       <Text >      
                           - appuyez sur <Image   
                                              source={require('./ico/cut.png')}  
                                              />      
                           pour le supprimer.  
                           </Text>         
                    <Text >              
                    </Text>            
             </View>                
         <View >                    
         {data.map(({ name, course, num }) => (
                            <View style={{flexDirection:"row", alignContent:"space-between"}}>
                            <TouchableHighlight
                                style={styles.u}
                                onPress= {Update(num, name, course)}
                                underlayColor="aliceblue"
                            >
                                <Image
                                    source={require('./ico/config.png')}
                                />     
                        </TouchableHighlight>
                            <TouchableHighlight
                                style={styles.u}
                                onPress={Delete(num)}
                                underlayColor="aliceblue"
                            >
                                <Image
                                    source={require('./ico/cut.png')}
                                />
                            </TouchableHighlight>
                            <View style={{width:"90%",flexDirection:"row", justifyContent:"space-evenly",alignItem:"center",alignContent:"space-around", paddingVertical:10}}>
                                <Text>{name}</Text>
                                <Text>{course}</Text>
                            </View>
                            </View>
                          ))}    
                        </View>
                    </ScrollView>
                    <Text >
    
                    </Text>
                <View style= { {width:"50%", alignSelf:"center"} }>    
                    
                    <TouchableHighlight
                                style={styles.u}
                                onPress={ReadRecords}
                                underlayColor="aliceblue"
                    >
                                <Text>Actualiser la table</Text>
                            </TouchableHighlight>
                </View>
                <Text >
    
                </Text>
            </View>
            
        )}
    }   

  const InsertRecord =() => {   
              if (studentName.length == 0 || course.length ==0)
                    {
                    alert ("champ manquant")
                    }
                else
                     {
                     var CrudAPIURL="https://code.dhumbert.info/mycrud.php";
                     var Headers={
                        'Accept':'Application/JSON',
                        'Content-Type':'Application/JSON'
                     };
                     var Data={
                        "op":"create",
                        studentName : studentName,
                        course : course,
                     };
                     /*alert(studentName);*/
                     fetch(
                         CrudAPIURL,
                         {
                            method: 'POST',
                            headers: Headers,
                            body: JSON.stringify(Data),
                         }
                     )
                     .then( (response) => response.json())
                     .then( (response) =>
                        {
                            /*alert(response.Message);*/
                            setStudentName("");
                            setCourse("");
                            setColoreBrderInputText("aliceblue");   
                      })
                     .catch( (error) =>
                        {
                            alert("error"+error);
                        })
                        }
        }
        
    const Inscrire =() => {
        return
            <View>
                <View style={{width:"100%", backgroundColor:"coral",}}>
                    <Text style={{ textAlign:"center", fontWeight :"bold",fontSize:20 }}>
                        - Ajouter un enregistrement -
                    </Text>
                </View>  
               <TextInput
                    style= { [styles.input, {borderColor:colore,width:220} ]}
                    placeholder={"nom de l'étudiant : "}
                    onChangeText={setStudentName}
                    value={studentName}
                    maxLength={24}
                    onFocus={colore => setColoreBorderInputText("red")}
                />   
          <TextInput
                style= { [styles.input, {borderColor:colore,width:220} ]}
                placeholder={"nom du cours : "}
                onChangeText={setCourse}
                value={course}
                maxLength={24}
                onFocus={colore => setColoreBorderInputText("red")}
            />
            <View style= { {width:"50%", alignSelf:"center"} }>    
                <Button
                    style= {styles.button }
                    title={"Enregistrer"}
                    onPress={InsertRecord}
                />
            </View>
        </View>
    )}

    const Update = (arg1, arg2, arg3 ) => () => {   
            navigation.navigate('UpdateCrud',{
                num: arg1,
                name: arg2,
                course: arg3,
            });
                        
    } 
    const Delete = (arg) => () => {
        /*alert("delete = " + arg);*/
        var CrudAPIURL="https://code.dhumbert.info/mycrud.php";
                      
        var Headers={
            'Accept':'Application/JSON',
            'Content-Type':'Application/JSON'
            };
        var Data={
            "op":"delete",
            num : arg,
            };
        fetch(
            CrudAPIURL,
            {
                method: 'POST',
                headers: Headers,
                body: JSON.stringify(Data),
            })
                .then( (response) => response.json())
                .then( (response) =>
                    {
                    alert(response.Message);
                    })
                .catch( (error) =>
                    {
                        alert("error"+error);
                        console.error(error);
                    })            
    }
    
    
    ReadRecords();
    return(
        <>
          <View style={styles.container, {backgroundColor:"lightcyan"}}>
            { Lire()}
         </View>
         <View style={styles.container , {backgroundColor:"lightcyan"}}>
            {Inscrire()}
         </View>
        </>
        )
} 

const styles = StyleSheet.create({
  container: {
    flex: 1,
    flexWrap: "wrap",
    width:"100%",
    marginTop: 8,
    backgroundColor: "aliceblue",
  },
  button: {
    paddingHorizontal: 8,
    paddingVertical: 10,
    borderRadius: 8,
    backgroundColor: "oldlace",
    alignSelf: "flex-start",
    marginHorizontal: "2%",
    marginBottom: 6,
    minWidth: "48%",
    textAlign: "center",
  },
  u: {
    paddingHorizontal: 8,
    paddingVertical: 6,
    borderRadius: 4,
    backgroundColor: "dodgerblue",
    alignSelf: "flex-start",
    marginHorizontal: "1%",
    marginBottom: 6,
    marginTop: 6,
    minWidth: 40,
    textAlign: "center",
  },
  input: {
    height: 40,
    margin: 12,
    borderWidth: 1,
    padding: 10,
  },


}); 

export default Crud;