diff --git a/README.md b/README.md index 24f6e39d87dd0e265d143e9f09510ebe9f76cb3b..29a97d47711b0f8b018290024e1c0178a099025d 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 0000000000000000000000000000000000000000..e3bf74abdf3795b9a12bddc1c0e8d3fc487a609f --- /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 98fefc72916afc2cb4f2032275bb04438cbc797a..10ffabc3443c49142df168bf982de5d5dc74b3c6 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 4b7e719a5b7c6b50e988fe7da76539ddac2b194e..724d612a4e9c8f43d2e187ad0a3dcdae963ff63c 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 0000000000000000000000000000000000000000..1109b60a0e4e3b3923b3a212de38d08d7d619651 --- /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 0000000000000000000000000000000000000000..4ab55cb8e596768e0c766e595d9ae801509f4549 --- /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 b6bdb818a7d343247d5a9d614908ebbdcb5b0d91..3cddc9b804f58fe9650d3e64138430308ed83a1a 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 0000000000000000000000000000000000000000..d44851e50f3625ced570637cebb6ad7ba39eb038 --- /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