From 18b2de400401fe8b8d1109dd558dac19cf94a10a Mon Sep 17 00:00:00 2001
From: Jean-Christophe <>
Date: Wed, 24 Jan 2024 15:56:31 +0100
Subject: [PATCH] =?UTF-8?q?useEffect=20hook=20=C3=A0=20la=20cr=C3=A9ation?=
 =?UTF-8?q?=20du=20composant?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 README.md                                     |  5 +-
 src/assets/style/personListing.css            |  5 ++
 src/components/person.component.jsx           |  8 ++-
 src/components/personListing.component.jsx    | 52 ++++++++++++-------
 .../personListingController.component.jsx     | 38 ++++++++++++++
 src/components/person_class.jsx               | 22 ++++++++
 src/scripts/main.js                           |  7 +--
 src/util/mockAPI.js                           | 15 ++++++
 8 files changed, 123 insertions(+), 29 deletions(-)
 create mode 100644 src/assets/style/personListing.css
 create mode 100644 src/components/personListingController.component.jsx
 create mode 100644 src/components/person_class.jsx
 create mode 100644 src/util/mockAPI.js

diff --git a/README.md b/README.md
index 24f6e39..29a97d4 100644
--- a/README.md
+++ b/README.md
@@ -49,7 +49,10 @@ où `tag` peut prendre comme valeur :
 * `v5.2` : modification  et état courant : mise en évidence du problème  
   voir `/src/components/star.jsx`
 * `v5.3` : modification  et état courant : utilisation d'une fonction en argument de `setOn` pour modifier l'état à partir de la valeur précédente    
-  voir `/src/components/star.component.jsx` (et `/src/components/person.component.jsx`)
+  voir `/src/components/star.jsx` (et `/src/components/person.component.jsx`)
+* `v5.5` : cycle de vie du composant : utilisation du hook `useEffect` pour agir au moment de la création du composant : juste après le premier rendu.  
+  voir `/src/components/personListing.jsx` 
+
 
 Faire ```git checkout main``` pour revenir à la version finale.
 
diff --git a/src/assets/style/personListing.css b/src/assets/style/personListing.css
new file mode 100644
index 0000000..e3bf74a
--- /dev/null
+++ b/src/assets/style/personListing.css
@@ -0,0 +1,5 @@
+div.personListing {
+  border : dashed thin black ;
+  padding : 10px;
+  margin : 5px;
+}
diff --git a/src/components/person.component.jsx b/src/components/person.component.jsx
index 98fefc7..10ffabc 100644
--- a/src/components/person.component.jsx
+++ b/src/components/person.component.jsx
@@ -1,17 +1,15 @@
-import { useState  } from 'react';
+import { useState } from 'react';
 
 // import stysheet defining style specific to this component
-import './assets/style/person.css';
+import '../assets/style/person.css';
 
 /*
 * define a component that uses props, props is a javascript object
 */
-const Person = ( { name = 'Anonymous' , age , delay } ) => {
+const Person = ( { name = 'Anonymous', age, started, delay } ) => {
    
    const [ currentAge, setCurrentAge ] = useState(age);
 
-   // become older every delay ms
-   setInterval( () => setCurrentAge( previousCurrentAge => previousCurrentAge + 1 ), delay);
 
    return (
       <div className="person">Here is :
diff --git a/src/components/personListing.component.jsx b/src/components/personListing.component.jsx
index 4b7e719..724d612 100644
--- a/src/components/personListing.component.jsx
+++ b/src/components/personListing.component.jsx
@@ -1,22 +1,38 @@
-import React from 'react';
+import { useState, useEffect } from 'react';
+
+import { mockFetch } from '../util/mockAPI.js';
+
+import '../assets/style/personListing.css';
 
 import Person from './person.component.jsx';
 
-/*
-* props.persons is an Array, here we assume with at least two elements
-* Here a list of components is built, but no "key" property is provided => /!\ pb, see console
-*/
-const PersonListing = ({ persons , delay }) => {
-      const personComponents = persons.map(person => <Person 
-                                                         {...person}
-                                                         key={person.id} 
-                                                         delay = { delay }
-                                                      />);
-      return (
-         <div>
-            People getting older every <span class="highlight">{delay}</span> seconds
-            {personComponents}
-         </div>
-      );
-   }
+
+const PersonListing =  props  => {
+   const  { started, delay } = props;
+
+   const [persons, setPersons ] = useState([]);
+
+
+   useEffect( () => {
+      console.log('component did mount');
+      const fetchData = async () => {
+         const data = await mockFetch('http://source.of.data/persons',1000);
+         setPersons( data );
+      }      
+      fetchData();            
+   }, []);
+
+   const personComponents = persons?.map(person => <Person 
+                                                      {...person}
+                                                      {...props}                                                      
+                                                      key={person.id}                                                       
+                                                   />);
+
+   return (
+      <div className="personListing">
+         People getting older every {delay} seconds
+         {personComponents}
+      </div>
+   );
+}
 export default PersonListing;
diff --git a/src/components/personListingController.component.jsx b/src/components/personListingController.component.jsx
new file mode 100644
index 0000000..1109b60
--- /dev/null
+++ b/src/components/personListingController.component.jsx
@@ -0,0 +1,38 @@
+import { useState } from 'react';
+
+import PersonListing from './personListing.component.jsx';
+
+const PersonListingController = ({ initialDelay = 250 }) => {
+
+    const [ closed, setClosed ] = useState(false);
+    const [ started, setStarted ] = useState(false);
+    const [ delay, setDelay ] = useState(initialDelay)
+
+    const startStop = () => setStarted( previousStarted => ! previousStarted);
+    const closeComponent = () => setClosed(true);
+
+    const changeDelay = newDelay => setDelay(newDelay);
+
+    if (closed)
+        return null;
+    // else
+    return (
+            <div>
+                <div className = 'controller'>
+                    <button onClick= { startStop }>
+                        { started ? 'Stop' : 'Start'}
+                    </button>
+                    <button onClick= { () => changeDelay(250) }>Delay = 250</button>
+                    <button onClick= { () => changeDelay(1000) }>Delay = 1000</button>
+                    <button onClick= { closeComponent }>Close</button>
+                </div>
+                <PersonListing
+                    delay = { delay }
+                    started = { started }
+                />
+            </div>
+            );
+
+}
+
+export default PersonListingController;
\ No newline at end of file
diff --git a/src/components/person_class.jsx b/src/components/person_class.jsx
new file mode 100644
index 0000000..4ab55cb
--- /dev/null
+++ b/src/components/person_class.jsx
@@ -0,0 +1,22 @@
+import React from 'react';
+
+import '../style/person.css';
+
+/*
+ * define component as a class that extends React.component
+*/
+export default class Person extends React.Component {
+   constructor(props) {
+      super(props);
+   }
+
+   render() {
+      const { name , age } = this.props;
+
+      const view = <div className="person">Here is :
+         <div>name : <span>{ name }</span> </div>
+         <div>age  : <span>{ age }</span> </div>
+      </div>
+      return view;
+   }
+}
diff --git a/src/scripts/main.js b/src/scripts/main.js
index b6bdb81..3cddc9b 100644
--- a/src/scripts/main.js
+++ b/src/scripts/main.js
@@ -1,14 +1,11 @@
 import { createRoot } from 'react-dom/client';
 
-// import React component
-import Star from '../components/star.component.jsx'
+import PersonListingController from '../components/personListingController.component.jsx';
 
    const bootstrapReact = () => {
       const root = createRoot(document.getElementById('insertReactHere')); 
 
-      const component = <> 
-                           <Star /> <Star />  <Star />
-                        </>
+      const component = <PersonListingController />;
 
       root.render(component);
    }
diff --git a/src/util/mockAPI.js b/src/util/mockAPI.js
new file mode 100644
index 0000000..d44851e
--- /dev/null
+++ b/src/util/mockAPI.js
@@ -0,0 +1,15 @@
+
+// used to "simulate" data fetching from some URL, here personsData is returned
+/*
+@param timetout simulate fetching delay, in ms, choose some high value (e.g. 2000) to highlight asynchronous operation
+*/
+import personsData from '../data/personsData.js';
+const mockFetch = async (mockURL, timeout = 10) => {
+   return await new Promise(resolve => setTimeout(() => {
+                                                         console.log(`simulate fetching data from ${mockURL}`);
+                                                         resolve(personsData);
+                                                        }, 
+                                                  timeout));        // simulate a 'timeout' duration for fetching operation
+}
+
+export { mockFetch };
\ No newline at end of file
-- 
GitLab