Application React (portail)

De Wiki1000
Version du 18 septembre 2020 à 08:10 par Syfre (discuter | contributions)
(diff) ← Version précédente | Voir la version courante (diff) | Version suivante → (diff)

Sommaire


React est une librairie javascript utilisée pour développer des interfaces utilisateurs.

Si vous souhaitez utiliser React dans une application html suivez les recommandations suivantes :

  • Configurez votre service 1000 pour permettre le développement de l'application
  • Créez une application html dans Sage FRP 1000
  • Créez un projet React.
  • Configurez le projet React.

Environnement

Environnement de développement

L'environnement de développement comprend deux éléments :

  • L'environnement de développement React dans lequel vous pouvez réaliser une grande partie des développements.
  • L'environnement de développement Sage FRP 1000 utilisé pour développer les APIs utilisées par votre application html.

Environnement de production

Lorsque votre développement est terminé vous pouvez générer un projet statique React qui sera le contenu de votre application html.

Les différences entre l'environnement de développement et le projet statique de production sont les suivantes :

  • L'environnement de développement utilise des URLs absolue pour accéder aux APIs 1000, l'environnement de production utilise des URLs relatives.
  • L'environnement de développement utilise un jeton d'authentification pour s'identifier auprès de Sage FRP 1000, l'environnement de production utilise les cookies de session de l'application hôte Sage FRP 1000.

Pour configurez les environnements de développement et de production utilisez les fichiers d'environnement de React et des variables d'environnement pour définir les schémas d'URLs et le token d'authentification.

Création des projets

Création de l'application html

Dans le concepteur de modèle créer une application html en choisissant n'importe quel template. Celui-ci sera remplacé par la suite et n'a donc pas d'importance.

Création du projet React

Créer le projet React en utilisant les outils et bonne pratiques standard de React, ce projet doit être placé dans un répertoire différent du répertoire de déploiement de l'application html de Sage FRP 1000.

Configuration

Configuration de l'application Desktop

Vous pouvez utiliser le serveur HTTP de développement de l'application Desktop pour tester votre projet React.

Pour cela, dans le concepteur de modèle :

  • Déployer les applications mobiles
  • Démarrez le serveur HTTP

Configurez ensuite l'application React pour utilisez l'adresse du serveur de développement (http://localhost:8080/sdata/)

Configuration du service 1000

Vous pouvez utiliser un service 1000 pour tester et valider vos développement.

Pour permettre à l'application React en cours de développement d'accéder aux APIs Sage FRP 1000 il est nécessaire d'autoriser les accès cross-origin.

Dans le fichier de configuration du service 1000 :

  ...
  HTTP CORS Allow origin=*
  ...

Générez un token d'authentification pour le dossier et l'application Sage FRP 1000 dans laquelle vous développez.

Tip-20px.png Tip : Ces paramétrages ne sont pas nécessaires sur un service Sage FRP 1000 de production, ils sont utilisés uniquement en développement

Configuration du projet React

Modification pour générer une application relative à index.html

Cette modification permet de générer un site statique de production relatif au fichier index.html.

Dans package.json ajouter la variable homepage = ".'

{
  "name": "myapp",
  "version": "0.1.0",
  "private": true,
  "homepage": ".",
  "dependencies": ....
  ....
}

Modification pour copier l'application statique dans le dossier de l'application html de FRP 1000

Cette modification permet de copier le site statique de production dans le dossier de déploiement de l'application html de Sage FRP 1000.

Modifier package.json en ajoutant une section postbuild :

{
  "name": "myapp",
  "version": "0.1.0",
  "private": true,
  "homepage": ".",
  ...
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "postbuild": "cp -r -f ./build/* /c/LocalSite900/htmls/testreact",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  ...
}
Tip-20px.png Tip : La syntaxe précédente correspond à l'utilisation de bash, si vous utilisez le terminal Windows modifiez l'ordre de copie en conséquence.

Modification pour gérer des variables d'environnement pour configurer l'application

Créer un fichier ".env.development" et un fichier ".env.production" à la racine de l'application React

REACT_APP_NAME=Sage FRP 1000 (development)
REACT_APP_API_URL=https://localhost/sdata/
REACT_APP_API_PACKAGE=testreactpackage
REACT_APP_API_TOKEN=1000...BD0D5CBA4F4864AFA7
REACT_APP_NOT_SECRET_CODE=Sage FRP 1000 (production)
REACT_APP_API_URL=../../server/sdata/
REACT_APP_API_PACKAGE=testreactpackage
Tip-20px.png Tip : Ces variables correspondent à l'utilisation de la librairie ApiFetch.js qui encapsule l'appel à la fonction fetch() de javascritpt, voir ci-dessous
Tip-20px.png Tip : L'url de l'API (REACT_APP_API_URL) dépend si vous développez en utilisant le serveur de développement de l'application Desktop ou un service 1000

Appel des APIs Sage FRP 1000 à partir des composants React

La méthode traditionnelle consiste à utiliser des appels REST via la librairie javascript fetch() dans la méthode componentDidMount() des composants React.

Pour tenir compte de la différence entre l'environnement de développement et l'environnement de production, vous pouvez encapsuler l'appel à fetch() pour prendre en compte de façon transparente ces différences.

Par exemple, voici une encapsulation de la fonction fetch() qui permet de gérer les appels aux APIs Sage FRP 1000 :

//Credit 
//better-fetch from Swizec
//[email protected] 
//http://swizec.com
//https://github.com/Swizec/better-fetch

var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();

var _includeTrailingUrlSeparator = function(s) {
    if (s.substr(-1) !== '/') return s + '/'; else return s;
};

var apiConfiguration = {url:'',  package:'', headers:{'Content-Type': 'application/json'} };

var apiFetch = function apiFetch(methodName) {

    var params = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
    params.headers = Object.assign({}, headerDict(params.headers), apiConfiguration.headers);
    params.credentials = 'same-origin';
    params.method = 'POST';

    var aurl = apiConfiguration.url;
    if (methodName.indexOf('/') > -1) 
     aurl = aurl+methodName; 
    else
     aurl = aurl+apiConfiguration.package+'/'+methodName; 

    return fetch(aurl, params);
};

var headerDict = function headerDict(headers) {
    var dict = {};

    if (headers instanceof Headers) {
        var _iteratorNormalCompletion = true;
        var _didIteratorError = false;
        var _iteratorError = undefined;

        try {
            for (var _iterator = headers.entries()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
                var _step$value = _slicedToArray(_step.value, 2),
                    key = _step$value[0],
                    value = _step$value[1];

                dict[key] = value;
            }
        } catch (err) {
            _didIteratorError = true;
            _iteratorError = err;
        } finally {
            try {
                if (!_iteratorNormalCompletion && _iterator.return) {
                    _iterator.return();
                }
            } finally {
                if (_didIteratorError) {
                    throw _iteratorError;
                }
            }
        }
    } else {
        dict = headers;
    }

    return dict;
};

apiFetch.setUrl = function (url) {

    apiConfiguration.url = url;
};
 
apiFetch.setDefaultHeaders = function (headers) {
    apiConfiguration.headers = headerDict(headers);
};

apiFetch.throwErrors = function (response) {
    if (!response.ok) {
        var err = new Error(response.statusText);
        err.response = response;
        throw err;
    }
    return response;
};

apiFetch.initializeFromEnv = function() {

    // REACT_APP_API_URL
    //
    // In development mode:
    //  must be the absolute url to the service
    //  ex : https://myhost/sdata/
    //
    // In production mode
    //  must be the relative path
    //  ex : ../../server/sdata
    
    // REACT_APP_API_PACKAGE
    //
    //  should be the default package name used for this app
    //  If the call doesn't include a package name this package is used. 

    // REACT_APP_API_TOKEN
    // 
    // Use only in development mode
    //  must be a valid authentication token

    apiConfiguration.url = _includeTrailingUrlSeparator(process.env.REACT_APP_API_URL);
    apiConfiguration.package = process.env.REACT_APP_API_PACKAGE;

    if (process.env.NODE_ENV === 'development') {
        apiConfiguration.headers['Authorization'] = 'Bearer '+ process.env.REACT_APP_API_TOKEN;
    };

    //console.log('api headers',apiConfiguration.headers);
 };

module.exports = apiFetch;

Cette librairie doit être configurée par un appel à initializeFromEnv() dans le fichier index.js de l'application React :

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import fetch from './ApiFetch.js'

fetch.initializeFromEnv();

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

Dans un composant React importez simplement cette librairie et appelez fetch() :

Ici le composant appel la fonction getData() du paquet par défaut défini dans les fichiers d'environnement.

import React, { Component } from 'react';
import fetch from './ApiFetch.js'

class App extends Component {
    state = {
        data: []
    };
    
    componentDidMount() {

       fetch('getdata')
            .then(result => result.json())
            .then(result => {
                this.setState({
                  data: result.agencies
                })
            });
    }

    render() {
        const { data } = this.state;

        console.log(data);

        const result = data.map((entry, index) => {
            console.log(entry);
            return <li key={entry.id}>{entry.city}</li>;
        });

        return <div className="container"><ul>{result}</ul></div>;
    }
}

export default App;

Voir aussi :

Outils personnels