From 59a86d5e10129016e9922fbe3fb9b51fe2a7471e Mon Sep 17 00:00:00 2001
From: Jean-Christophe <jean-christophe.routier@univ-lille.fr>
Date: Mon, 29 Jan 2024 09:05:48 +0100
Subject: [PATCH] =?UTF-8?q?composants=20non=20control=C3=A9s=20et=20useRef?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 readme.md                                     |  3 +-
 src/assets/style/addPerson.css                |  9 +++
 src/components/addPerson.component.jsx        | 42 +++++++++++++
 src/components/app.component.jsx              | 63 ++++++++++---------
 .../personListingController.component.jsx     |  5 +-
 .../personListingControls.component.jsx       |  6 +-
 6 files changed, 97 insertions(+), 31 deletions(-)
 create mode 100644 src/assets/style/addPerson.css
 create mode 100644 src/components/addPerson.component.jsx

diff --git a/readme.md b/readme.md
index 4307ee8..7818c52 100644
--- a/readme.md
+++ b/readme.md
@@ -67,7 +67,8 @@ où `tag` peut prendre comme valeur :
   voir `/src/components/personListingControls.component.jsx` et `/src/components/personListingController.component.jsx`  
 * `v6.2` : refactorisation des composants, on continue à "remonter l'état"  
    voir `/src/components/app.jsx`, `/src/components/personListingData.jsx`  
-
+* `v7` : exemple de composant avec des élément *non contrôlés* par *React*  
+  voir `/src/components/addPerson.jsx`  
 
 Faire ```git checkout main``` pour revenir à la version finale.
 
diff --git a/src/assets/style/addPerson.css b/src/assets/style/addPerson.css
new file mode 100644
index 0000000..99f8954
--- /dev/null
+++ b/src/assets/style/addPerson.css
@@ -0,0 +1,9 @@
+div.addPerson {
+  padding : 4px;
+  margin : 5px auto 0px 20px;
+  border : solid thin #BBB;
+  text-align : center;
+}
+div.addPerson input {
+  margin : 0px 5px;
+}
diff --git a/src/components/addPerson.component.jsx b/src/components/addPerson.component.jsx
new file mode 100644
index 0000000..b7eac3a
--- /dev/null
+++ b/src/components/addPerson.component.jsx
@@ -0,0 +1,42 @@
+import { useRef } from 'react';
+
+import '../assets/style/addPerson.css';
+
+const DEFAULT_NAME = 'Anonymous';
+const DEFAULT_AGE = 12;
+
+const AddPerson = ( { addPerson } ) => {
+
+    const nameInputRef = useRef(null);
+    const ageInputRef = useRef(null);
+
+    const handleClick = () => {
+        const person = {
+           name: nameInputRef.current.value || DEFAULT_NAME,
+           age: parseInt(ageInputRef.current.value) || DEFAULT_AGE
+        };
+        addPerson(person);
+        clearFields();
+     }
+  
+    const clearFields = () => {
+        nameInputRef.current.value = '';
+        ageInputRef.current.value = '';
+    }
+
+     return (
+        <div className="addPerson">
+           <input
+              type="text" placeholder="Name"
+              ref={nameInputRef}
+           />
+           <input
+              type="number" min="0" placeholder="Age"
+              ref={ageInputRef}
+           />
+           <button onClick={handleClick}>Add</button>
+        </div>
+     );
+}
+
+export default AddPerson;
\ No newline at end of file
diff --git a/src/components/app.component.jsx b/src/components/app.component.jsx
index 79920e6..ebf79f2 100644
--- a/src/components/app.component.jsx
+++ b/src/components/app.component.jsx
@@ -9,37 +9,44 @@ import { mockFetch } from '../util/mockAPI.js';
 
 const App = () => {
 
- const [persons, setPersons ] = useState([]);
+    const [persons, setPersons ] = useState([]);
 
- const fetchData = async () => {
-    const data = await mockFetch('http://source.of.data/persons',10);
-    setPersons( data );
- }      
+    const fetchData = async () => {
+        const data = await mockFetch('http://source.of.data/persons',10);
+        setPersons( data );
+    }      
 
- useEffect( () => {
+    useEffect( () => {
     fetchData();            
- }, []);
-
-  /* increment age of person with given id, state is updated */
-const incrementAge = (personId) => {
-    setPersons ( previousPersons => {
-                                        const olderPerson = previousPersons.find( person => person.id === personId );
-                                        olderPerson.age = olderPerson.age + 1;
-                                        return [...previousPersons];
-                                    });
-}
-
-return(
-    <div id="app">
-        <PersonListingController
-            persons = { persons }
-            incrementAge = { incrementAge }
-        />
-        <PersonListingData
-            persons = { persons }
-        />
-    </div>
-);
+    }, []);
+
+    /* increment age of person with given id, state is updated */
+    const incrementAge = (personId) => {
+        setPersons ( previousPersons => {
+                                            const olderPerson = previousPersons.find( person => person.id === personId );
+                                            olderPerson.age = olderPerson.age + 1;
+                                            return [...previousPersons];
+                                        });
+    }
+
+    const addPerson = person => {
+        const newId = `A${persons.length + 1}`;
+        const newPerson = { ...person, id: newId };
+        setPersons(previousPersons => [...previousPersons, newPerson] );
+    }
+
+    return(
+        <div id="app">
+            <PersonListingController
+                persons = { persons }
+                incrementAge = { incrementAge }
+                addPerson = { addPerson }
+            />
+            <PersonListingData
+                persons = { persons }
+            />
+        </div>
+    );
 }
 
 export default App;
\ No newline at end of file
diff --git a/src/components/personListingController.component.jsx b/src/components/personListingController.component.jsx
index c477855..ef0c744 100644
--- a/src/components/personListingController.component.jsx
+++ b/src/components/personListingController.component.jsx
@@ -9,6 +9,8 @@ const INITIAL_DELAY= 1000;
 
 const PersonListingController = ( props ) => {
 
+    const { addPerson } = props; 
+
     const [ closed, setClosed ] = useState(false);
     const [ started, setStarted ] = useState(false);
     const [ delay, setDelay ] = useState(INITIAL_DELAY);
@@ -40,7 +42,8 @@ const PersonListingController = ( props ) => {
                     changeDelay={changeDelay}
                     closeAction={closeComponent}
                     startStop={startStop}
-                    />);
+                    addPerson={addPerson}
+                />);
     }
 
     return (
diff --git a/src/components/personListingControls.component.jsx b/src/components/personListingControls.component.jsx
index f233637..6157941 100644
--- a/src/components/personListingControls.component.jsx
+++ b/src/components/personListingControls.component.jsx
@@ -1,8 +1,9 @@
 import '../assets/style/personControls.css';
 
 import DelayButton from './delayButton.component.jsx';
+import AddPerson from './addPerson.component.jsx';
 
-const PersonListingControls = ( { started, closed, changeDelay, closeAction, startStop } ) => {
+const PersonListingControls = ( { started, closed, changeDelay, closeAction, startStop, addPerson } ) => {
 
     const buildDelayButtons = () => {
         const delayButtons = [250,1000,3000].map ( delay => <DelayButton delay = { delay }
@@ -21,6 +22,9 @@ const PersonListingControls = ( { started, closed, changeDelay, closeAction, sta
             <button onClick= { closeAction }>
                 { closed ? 'Open'  : 'Close' }
             </button>
+            <AddPerson
+                addPerson={ addPerson }
+            />
         </div>
     );    
 }
-- 
GitLab