Aurélien Tabard - Université Claude Bernard Lyon 1
Programmation Réactive
Principes fondamentaux et application au Web
1
Aurélien Tabard - Université Claude Bernard Lyon 1
Plan
‣ Quoi et pourquoi la réactivé
‣ Les principes de la programmation réactive
‣ Réactivité et Vue
2
Aurélien Tabard - Université Claude Bernard Lyon 1
Qu’est ce que la programmation réactive ?
Une approche visant à mieux gérer les flux Deux types de flux
‣ Des événements discrets : frappe clavier
‣ Des évènements continus ou comportements : position souris
Idée : dépasser les callbacks ou le patron Observer.
3
Aurélien Tabard - Université Claude Bernard Lyon 1
Ou avez vous vu ça ?
4 http://www.hanselsolutions.com/blog/surf-talk/shiny-surf.html#/9
Aurélien Tabard - Université Claude Bernard Lyon 1
Ou avez vous vu ça ?
5 http://www.hanselsolutions.com/blog/surf-talk/shiny-surf.html#/9
Aurélien Tabard - Université Claude Bernard Lyon 1
Ou avez vous vu ça ?
6 http://www.hanselsolutions.com/blog/surf-talk/shiny-surf.html#/9
Aurélien Tabard - Université Claude Bernard Lyon 1
Pourquoi la prog. réactive sur le Web ?
7
Aurélien Tabard - Université Claude Bernard Lyon 1
Les origines de React
8
Aurélien Tabard - Université Claude Bernard Lyon 1
Pourquoi la programmation réactive ?
‣ Gestion d’évènements et de l’asynchrone
‣ Faible latence (contraintes sur les temps de réponse)
‣ Flux de données importants (et rapides).
‣ Tolérance aux fautes
9
Aurélien Tabard - Université Claude Bernard Lyon 1
Exemples
À vous
10
Aurélien Tabard - Université Claude Bernard Lyon 1
Les bibliothèques Javascript
11
Aurélien Tabard - Université Claude Bernard Lyon 1
Plan
‣ Quoi et pourquoi la réactivé
‣ Les principes de la programmation réactive
‣ Réactivité et Vue
12
Aurélien Tabard - Université Claude Bernard Lyon 1
Les principes de base
‣ Responsive,
‣ Résilient,
‣ Élastique,
‣ Orienté message
13
Aurélien Tabard - Université Claude Bernard Lyon 1
Responsive
‣ Réponse en temps voulu, si possible
‣ Temps de réponses rapides et fiables (limites hautes)
14
Aurélien Tabard - Université Claude Bernard Lyon 1
Résilient
‣ Résiste à l’échec
‣ Principes :
Réplication, conteneurs, isolement, délégation
‣ On fait en sorte qu’un échec n’impacte qu’un seul composant
15
Aurélien Tabard - Université Claude Bernard Lyon 1
Élastique
Le système reste réactif en cas de variation de la charge de travail.
‣ Pas de point central
‣ Pas de goulot
‣ Distribution des entrées entre composants
16
Aurélien Tabard - Université Claude Bernard Lyon 1
Orienté message
‣ Passage de messages asynchrones -> Couplage faible, isolation
‣ Pas de blocage, les composants consomment les ressources quand ils peuvent
17
Aurélien Tabard - Université Claude Bernard Lyon 1
Un concept important : l’immuabilité
Objet immuable (Immutable object)
‣ Objet dont l'état ne peut pas être modifié après sa création
‣ Opposé d’objet variable
Facilite la prog. purement fonctionnelle (pratique pour plein de choses, évite les effets de bords, facilite le undo)
Une seule source de “vérité”
Facilite le caching
Mais ce n’est pas forcément assez : https://codewords.recurse.com/issues/six/immutability-is-not-enough
18
Interaction Design – SS2012 Aurélien Tabard - Université Claude Bernard Lyon 1
Un exemple de transformation
https://gist.github.com/staltz/868e7e9bc2a7b8c1f754
Aurélien Tabard - Université Claude Bernard Lyon 1
Plan
‣ Quoi et pourquoi la réactivé
‣ Les principes de la programmation réactive
‣ Réactivité et Vue
20
Aurélien Tabard - Université Claude Bernard Lyon 1
Vous avez aimé MVC voilà MVVM
21
Aurélien Tabard - Université Claude Bernard Lyon 1
MVVM avec Vue
22
Aurélien Tabard - Université Claude Bernard Lyon 1
En pratique avec Vue
23
Data
Aurélien Tabard - Université Claude Bernard Lyon 1 24
Aurélien Tabard - Université Claude Bernard Lyon 1
Un DOM Virtuel
25 https://teropa.info/blog/2015/03/02/change-and-its-detection-in-javascript-frameworks.html
DOM
Aurélien Tabard - Université Claude Bernard Lyon 1
Flux de données avec Vue
Deux approches au data-binding (lien entre données et vue):
‣ Two way data-binding
‣ One way data binding
Le flux de données est uni-directionnel, les enfants ne modifient pas les données qui sont contrôlées par leur parents.
Mais les enfants peuvent demander au parent de se mettre à jour (et tout rafraichir depuis le modèle).
26
Aurélien Tabard - Université Claude Bernard Lyon 1
Deux façons de gérer les données
‣ Données qui changent (mutable) : on utilise un état (data)
‣ Données qui ne changent pas (immutable) : on utilise des propriétés (props)
‣ On essaie de minimiser les données qui changent quitte à refaire des calculs
27
Aurélien Tabard - Université Claude Bernard Lyon 1
Vuex : gestion avancée des états
Aurélien Tabard - Université Claude Bernard Lyon 1
Vuex : gestion d’états
One-way data flow
State (état), source de
“vérité” pour l’application
View (vue), représentation de l’état (mapping déclaratif)
Actions, changements de l’état en réaction à des
entrées de l’utilisateur au
niveau de la vue (ou d’autres inputs)
29 https://vuex.vuejs.org/en/intro.html
Aurélien Tabard - Université Claude Bernard Lyon 1
Vue et v-model
‣ Un état géré dans chaque composant
30
Aurélien Tabard - Université Claude Bernard Lyon 1
Problèmes
‣ Plusieurs vues dépendent du même bout d’état
‣ Plusieurs actions de différentes vues vont changer (mutate) un même bout d’état
31
Aurélien Tabard - Université Claude Bernard Lyon 1
Solution: VueX
‣ l’état devient un gros singleton partagé par tous les composants
32
Aurélien Tabard - Université Claude Bernard Lyon 1
Vue + Vuex
33
Aurélien Tabard - Université Claude Bernard Lyon 1
Cas concret
34
Aurélien Tabard - Université Claude Bernard Lyon 1
Créer son store (vue2+vuex3)
// app.js
import Vue from 'vue'
import store from './store' import App from './components/
App.vue' new Vue({
store, // inject store to all children
el: '#app',
render: h => h(App) })
// store.js
import Vue from 'vue' import Vuex from 'vuex'
import mutations from './mutations' import actions from './actions'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
todos: […] // état initial },
actions, mutations })
35
https://vuex.vuejs.org/fr/guide/
Aurélien Tabard - Université Claude Bernard Lyon 1
Créer son store (vue3+vuex4)
import { createApp } from 'vue'
import { createStore } from 'vuex' // Create a new store instance.
const store = createStore({
state () { return {
todos: […]
} },
actions, mutations, })
const app = createApp({ /* your root component */ }) app.use(store)
36
https://next.vuex.vuejs.org/guide/
Aurélien Tabard - Université Claude Bernard Lyon 1
Les mutations
export const mutations = { addTodo(state, todo) {
state.todos.push(todo);
},
removeTodo(state, todo) {
state.todos.splice(state.todos.indexOf(todo), 1);
},
editTodo(state, { todo, text = todo.text, done = todo.done }) { const index = state.todos.indexOf(todo);
state.todos.splice(index, 1, { ...todo,
text, done, });
}, };
37
Aurélien Tabard - Université Claude Bernard Lyon 1
Les actions
export default {
addTodo ({ commit }, text) { commit('addTodo', {
text,
done: false })
},
removeTodo ({ commit }, todo) { commit('removeTodo', todo) },
toggleTodo ({ commit }, todo) { commit('editTodo',
{todo, done: !todo.done}
) },
editTodo ({ commit }, { todo, value }){
commit('editTodo',
{todo, text: value } )
},
toggleAll ({ state, commit }, done) { state.todos.forEach((todo) => {
commit('editTodo', { todo, done }) })
},
clearCompleted ({ state, commit }) { state.todos.filter(todo => todo.done) .forEach(todo => {
commit('removeTodo', todo) })
} }
38
Aurélien Tabard - Université Claude Bernard Lyon 1
Lien entre le composant TodoItem et le store
<template>
<li class="todo"
:class="{ completed: todo.done, editing:
editing }">
<div class="view">
<input class="toggle"
type="checkbox"
:checked="todo.done"
@change="toggleTodo(todo)">
<label v-text="todo.text"
@dblclick="editing = true”>
</label>
<button class="destroy"
@click=“removeTodo(todo)">
</button>
</div>
<input class="edit"
v-show="editing"
v-focus="editing"
:value="todo.text"
@keyup.enter="doneEdit"
@keyup.esc="cancelEdit"
@blur="doneEdit">
</li>
</template>
import { mapActions } from 'vuex' export default {
name: 'Todo', props: ['todo'], data () {…}, directives: {…}, methods: {
...mapActions([
'editTodo', 'toggleTodo', 'removeTodo' ]),
doneEdit (e) {
const value = e.target.value.trim() const { todo } = this
if (!value) {
this.removeTodo(todo) } else if (this.editing) { this.editTodo({
todo, value })
this.editing = false }
},
cancelEdit (e) {…}
} }
39