--- tags: ironhack, lecture, --- <style> .markdown-body img[src$=".png"] {background-color:transparent;} .alert-info.lecture, .alert-success.lecture, .alert-warning.lecture, .alert-danger.lecture { box-shadow:0 0 0 .5em rgba(64, 96, 85, 0.4); margin-top:20px;margin-bottom:20px; position:relative; ddisplay:none; } .alert-info.lecture:before, .alert-success.lecture:before, .alert-warning.lecture:before, .alert-danger.lecture:before { content:"👨‍🏫\A"; white-space:pre-line; display:block;margin-bottom:.5em; /*position:absolute; right:0; top:0; margin:3px;margin-right:7px;*/ } b { --color:yellow; font-weight:500; background:var(--color); box-shadow:0 0 0 .35em var(--color),0 0 0 .35em; } .skip { opacity:.4; } </style> ![logo_ironhack_blue 7](https://user-images.githubusercontent.com/23629340/40541063-a07a0a8a-601a-11e8-91b5-2f13e4e6b441.png) # React | Lifting State Up ![](https://i.imgur.com/TRqlasz.png) ## Learning Goals After this lesson you will be able to: - Understand how to pass data from child back to a parent component - Understand the importance of having a unique "source of truth" in your apps ## Introduction We've learnt how to **pass data from a parent component to a child component using props**. We’ve also learnt how to **change the data within the same component using state**. To summarize: *state belongs to the component itself and props are used to pass data to child components*. :::warning lecture - Les props permettent de passer des "choses" à un composant, depuis un autre composant dit "parent". - Les states eux sont "internes" au composant (cf. feelings) ::: ## Lifting State Up Would it also be possible to pass data from a child component back to a parent component? Yes, it is. 😀 It's called **lifting state up**. A more descriptive name would be *"establishing two way communication with the parent component"*. :::warning lecture Comment va t-on depuis un enfant passer des datas au parent ? ![](https://i.imgur.com/5cl4eG2.png) ::: :::info Lifting state up is done by passing a **handler function to the child component as a props**. ::: :::warning lecture Réponse : via une fonction de callback passé en prop à l'enfant, afin que celui-ci puisse l'appeler (image du téléphone a son enfant en ayant enregistré son numero d'avance dans le répertoire). ![](https://i.imgur.com/E61rEKB.png) ::: Try to understand how it works by analyzing the code first: <iframe src="https://codesandbox.io/embed/youthful-visvesvaraya-fxmmp?fontsize=14&hidenavigation=1&theme=dark" style="width:100%; height:500px; border:0; border-radius: 4px; overflow:hidden;" title="youthful-visvesvaraya-fxmmp" allow="geolocation; microphone; camera; midi; vr; accelerometer; gyroscope; payment; ambient-light-sensor; encrypted-media; usb" sandbox="allow-modals allow-forms allow-popups allow-scripts allow-same-origin" ></iframe> ( 🔝 To see the components, click on the 📄 in the upper left corner.) :::warning lecture Voir : https://codesandbox.io/s/youthful-visvesvaraya-fxmmp On review le code avec les étudiants: - `App.js` : classique - `ToDo.js` : `@updateToDoList` -- fonction permettant de supprimer une tâche de `this.state.tasks` (mal nommée ?) + reparler du spread `[...arr]` et de `splice` - `Task.js` : `onClick={event => this.props.deleteTask()}` -- utilisation de la fonction de callback `this.props.deleteTask` transmise ::: The `<ToDo/>` parent component holds multiple tasks in its state. These tasks are represented by simple strings. Based on this state, the `<ToDo/>` component renders the individual `<Task/>` child components. Every `<Task/>` will receive a props with the task string, a props with an index number that identifies the task and a props with a handler function. It's this function that enables the `<Task/>` component to communicate with its parent `<ToDo/>` component. When we click on a task, we'll call this function with the index number as an argument in order to notify the parent component that this task is completed. The parent will update the state and rerender is triggered. This time without the task clicked. :::info lecture To summarize - in React we can deal with data in 3 ways: - Pass data from a parent to a child component by passing props in the child ![](https://i.imgur.com/ILPSnon.png =150x) ```jsx <SomeChild someProp={value} /> ``` - Modify the data from within a component with ```jsx setState({someStateKey: "someValue"}); ``` - Pass data up from a child component to a parent component by passing a handler function from the parent to the child as a prop. In the example code this is ![](https://i.imgur.com/CvZvjxM.png =150x) ```jsx <SomeChild aHandlerFunction={updateToDoList} /> ``` ::: :::warning lecture NB: Autres stratégies: https://www.javascriptstuff.com/component-communication ::: :::warning lecture Nous avions déjà géré un delete depuis un enfant dans [IronContacts](https://github.com/ironhack-labs/lab-react-ironcontacts) : ![](https://i.imgur.com/rK8Dwhq.gif) ::: :::warning lecture Mais aussi dans [IronNutrition](https://github.com/ironhack-labs/lab-react-ironnutrition) pour ajouter un plat depuis `<AddBox>`: [![](https://docs.google.com/drawings/d/e/2PACX-1vRmyVhS19PPaEfYw6BfPmNUtVYhRqjFM-_5v5RBEV6WgIqSbwRKcrit6gAEHyWe84JJaI1h35xe-xON/pub?w=1623&h=1361)](https://docs.google.com/drawings/d/1DM5ZoDqIoMBKvQvGJwJjmlP2mBxIJiLoVsW_kOQ9SaU/edit) ([PDF version](https://trello-attachments.s3.amazonaws.com/5bea91c3d806ab4d09d331d7/5c7d09184479cf14f5729d4c/2c1866c94098f884aeaa5221e0879dd5/React___Lifting_State_Up_--_Ironhack.pdf)) 1. Click bouton de soumission du formulaire 2. `submit` event sur le `form` 3. onSubmit callback `@handleSubmit` 4. on fait appel à la fonction passée en `prop.onAdd` en lui envoyant le `state` courant (aka. `🍕`) 5. exécution de `app.addFood(🍕)` 6. ...etc ::: ## Interesting questions - Why do we have to bind updateToDoList? :::warning lecture Parler de `.bind(this)` depuis `onClick={handleClick.bind(this)}` ou bien depuis le constructor `this.handleClick = this.handleClick.bind(this)` ainsi que des arrow-functions en methods ::: - Can a child of a child component communicate with the parent of the first child? In other words, can grandparents communicate with their grandchildren? :::warning lecture Uniquement si l'enfant a passé la fonction de callback au petit-enfant (pour que lui aussi puisse l'appeler) / Parallele = uniquement si le parent a mis le numéro de son pere dans le téléphone de son fils (pour que son fils puisse appeler son grand-pere) ::: - And great grandparents with their great grandchildren? ## In class exercise Your turn. Create a shopping list from scratch. A `<ShoppingList/>` renders `<ShoppingItem/>`'s. If you click on a `<ShoppingItem/>`, you should notify `<ShoppingList/>` by 'lifting state up :::warning lecture A faire en forkant ce codesandbox : https://codesandbox.io/s/ecstatic-feistel-h6x3e Démo du résultat final : <!-- solution: https://codepen.io/abernier/pen/ywXLvX?editors=1010 --> <iframe height="300" style="width: 100%;" scrolling="no" title="ywXLvX" src="//codepen.io/abernier/embed/ywXLvX/?height=300&theme-id=32929&default-tab=result" frameborder="no" allowtransparency="true" allowfullscreen="true"> See the Pen <a href='https://codepen.io/abernier/pen/ywXLvX/'>ywXLvX</a> by Antoine BERNIER (<a href='https://codepen.io/abernier'>@abernier</a>) on <a href='https://codepen.io'>CodePen</a>. </iframe> Instructions : - 2 composants (en plus de `App`) : `<ShoppingList>`, `<ShoppingItem>` - au click sur un ingrédient, `ShoppingItem` doit notifier `ShoppingList` de l'ingrédient cliqué, et `ShoppingList` doit alors alerter : `"🥕 a été cliqué!"` NB: `ShoppingList` implémentera une méthode `breakingnews` ::: ### Bonus exercise For this exercise we will increase the complexity of our component tree with one extra layer. Make a component called `<MasterPlan/>`. This component will render several to `<ToDo/>`'s by passing down the tasks, the title of the list and a handler function as props. If all tasks of `<ToDo/>` are completed, so is the `<ToDo/>` list itself. Remove it from `<Masterplan/>`'s state. :::warning lecture Démo: https://nwyyj.csb.app/ <!-- solution: https://codesandbox.io/s/pensive-dew-nwyyj --> --- Dans `src/MasterPlan.js` : `data.json`: ```json { "legumes": ["🍅", "🥕", "🥔", "🌽"], "friandises": ["🍩", "🍫"] } ``` `MasterPlan.js`: ```jsx ... import json from './data.json' class MasterPlan extends React.Component { // 1. Définir un state `todos` valant ['legumes', 'friandises'] (ie: les clés du json) // 3. Implementer une méthode `deleteTodo` supprimant un élement du state `todos` // -> cette methode sera appelée qd toutes les taches d'une ToDo auront été complétées render() { // 2. Pour chacun des éléments du state `todos`, instancier un composant `<ToDo>` en lui passant les props suivantes : // - un `title`, eg: "legumes" // - une liste de `tasks`, eg: ["🍅", "🥕", "🥔", "🌽"] // - une fonction `alldone` à appeler qd cette ToDo sera complétée } } ... ``` `ToDo.js`: ```jsx class ToDo extends React.Component { // 1. Définir un state `tasks` valant un tableau des tâches recues en props // 3. Implémenter une méthode `deleteTask` supprimant un élément du state `tasks` render() { // 2. Pour chacune des taches du state `tasks`, instancier un composant `<Task>` en lui passant les props suivantes : // - une chaine `task`, eg: "🍅" // - une fonction `done` à appeler (par Task) qd l'utilisateur cliquera sur l'emoji } } ... ``` `Task.js`: ```jsx class Task extends React.Component { render() { // 1. faire le rendu d'une tache (afficher la chaine `task` reçue en props) } } ``` ::: ### Looking ahead Managing one layer of complexity is doable, like with the to do list and tasks. With the `masterplan` it's already starting to get tricky, but any more layers will make you mad! 🤯 Keep your React project as shallow as possible to maintain your sanity. Only add layers of complexity if it's really necessary. You'll find that there's often a simpler, more elegant solution. <small> There's also a library called Redux to deal with this issue, but that's outside the scope of this course and for most of your projects an overkill.</small> ## Another example of communication between components If you want to take a look at more complex example, you can check the following code snippet and see how components C and D communicate with each other: https://codesandbox.io/s/p7y3jk8pq0 ![Screenshot](https://i.imgur.com/AIxTu3g.png) :::warning lecture Ex très intéressant a expliciter avec les étudiants. Règle : > We recommend lifting the shared state up to their closest common ancestor. -- https://reactjs.org/docs/lifting-state-up.html ::: ## Summary In this lesson we got familiar with a concept of lifting the state up and how to pass data from child back to a parent component. We also saw the way to avoid mutating the state using the spread operator and making the copy of the array fist, before making any changes. ## Extra Resources - [8 things to learn in React before using Redux](https://www.robinwieruch.de/learn-react-before-using-redux/) - [Lifting State Up - official docs](https://reactjs.org/docs/lifting-state-up.html)