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