|
| 1 | +# Actions |
| 2 | + |
| 3 | +> Le azioni, action, in Vuex sono i cosidetti "Actions creator" nel mondo di Flux. Ma questo termine è fuorviante. |
| 4 | +
|
| 5 | +Le action sono semplici funzioni che inviano le mutation. Per convenzione, le action in Vuex si aspettano sempre un istanza di store come primo argomento, seguito da altri argomenti opzionali: |
| 6 | + |
| 7 | +``` js |
| 8 | +// l'action più semplice |
| 9 | +function increment (store) { |
| 10 | + store.dispatch('INCREMENT') |
| 11 | +} |
| 12 | + |
| 13 | +// una semplice azione con più argomenti |
| 14 | +// che sfrutta il distruttore dei ES2015 |
| 15 | +function incrementBy ({ dispatch }, amount) { |
| 16 | + dispatch('INCREMENT', amount) |
| 17 | +} |
| 18 | +``` |
| 19 | + |
| 20 | +La domanda può sorgere spontanea, perchè non inviamo direttamente le mutation senza passare per le azioni? Ricordate che **le mutation sono sempre sincrone**? Bene, tramite le action noi possiamo scavalcare questo problema in quanto, internamente ad una action, possiamo gestire codice asincrono! |
| 21 | + |
| 22 | +``` js |
| 23 | +function incrementAsync ({ dispatch }) { |
| 24 | + setTimeout(() => { |
| 25 | + dispatch('INCREMENT') |
| 26 | + }, 1000) |
| 27 | +} |
| 28 | +``` |
| 29 | + |
| 30 | +Un esempio pratico può essere il sistema di checkout di un carrello che richiede **chiamate asincrone ad API** e **l'invio di mutation multiple**: |
| 31 | + |
| 32 | +``` js |
| 33 | +function checkout ({ dispatch, state }, products) { |
| 34 | + // salviamo l'oggetto corrente |
| 35 | + const savedCartItems = [...state.cart.added] |
| 36 | + // inviamo una richiesta di checkout |
| 37 | + dispatch(types.CHECKOUT_REQUEST) |
| 38 | + // in questo caso le API accettano due callback per success e failure |
| 39 | + shop.buyProducts( |
| 40 | + products, |
| 41 | + // success |
| 42 | + () => dispatch(types.CHECKOUT_SUCCESS), |
| 43 | + // failure |
| 44 | + () => dispatch(types.CHECKOUT_FAILURE, savedCartItems) |
| 45 | + ) |
| 46 | +} |
| 47 | +``` |
| 48 | + |
| 49 | +Si noti che invece di aspettarsi un valore di ritorno, la gestione delle API asincrone è fatta chiamando altre mutation. Possiamo quindi definire una regola di base dove **l'unico effetto prodotto dalla chiamata ad azioni è l'invio di mutation**. |
| 50 | + |
| 51 | +### Chiamare gli Action nei Componenti |
| 52 | + |
| 53 | +Forse avrete notato che le azioni, e le funzioni legate ad esse, non possono essere chiamate direttamente senza una referenza all'istanza dello store. Tecnicamente si potrebbe fare chiamando `action(this.$store)` internamente ad un metodo, è comunque consigliato esporre un set di API dal componente tramite `vuex.actions`, per esempio: |
| 54 | + |
| 55 | +``` js |
| 56 | +// internamente ad un componente |
| 57 | +import { incrementBy } from './actions' |
| 58 | + |
| 59 | +const vm = new Vue({ |
| 60 | + vuex: { |
| 61 | + getters: { ... }, // i getter |
| 62 | + actions: { |
| 63 | + incrementBy // Utilizziamo la sintassi ES6 per gli oggetti |
| 64 | + } |
| 65 | + } |
| 66 | +}) |
| 67 | +``` |
| 68 | + |
| 69 | +Il codice appena visto lega l'azione `incrementBy` con l'istanza di uguale nome nello store ed espone tale istanza al componente tramite `vm.incrementBy`. Tutti gli argomenti passati ad `vm.incrementBy` saranno passai prima all'azione e poi allo store in questo modo: |
| 70 | + |
| 71 | +``` js |
| 72 | +vm.incrementBy(1) |
| 73 | +``` |
| 74 | + |
| 75 | +è uguale a scrivere: |
| 76 | + |
| 77 | +``` js |
| 78 | +incrementBy(vm.$store, 1) |
| 79 | +``` |
| 80 | + |
| 81 | +ma il beneficio di avere tale sintassi è che ora possiamo usare: |
| 82 | + |
| 83 | +``` html |
| 84 | +<button v-on:click="incrementBy(1)">Incrementa di uno</button> |
| 85 | +``` |
| 86 | + |
| 87 | +Ovviamente potete utilizzare un altro nome dentro il componente, l'importante è referenziarlo all'istanza nello store: |
| 88 | + |
| 89 | +``` js |
| 90 | +// il componente |
| 91 | +import { incrementBy } from './actions' |
| 92 | + |
| 93 | +const vm = new Vue({ |
| 94 | + vuex: { |
| 95 | + getters: { ... }, |
| 96 | + actions: { |
| 97 | + plus: incrementBy // usiamo un altro nome |
| 98 | + } |
| 99 | + } |
| 100 | +}) |
| 101 | +``` |
| 102 | + |
| 103 | +Ora l'action sarà legata a `vm.plus` invece che `vm.incrementBy`. |
| 104 | + |
| 105 | +### Action Inline |
| 106 | + |
| 107 | +Se un'azione è specifica per un determinato componente, allora possiamo usare una scorciatoia e definirla inline: |
| 108 | + |
| 109 | +``` js |
| 110 | +const vm = new Vue({ |
| 111 | + vuex: { |
| 112 | + getters: { ... }, |
| 113 | + actions: { |
| 114 | + plus: ({ dispatch }) => dispatch('INCREMENT') |
| 115 | + } |
| 116 | + } |
| 117 | +}) |
| 118 | +``` |
| 119 | + |
| 120 | +### Legare tutte le Action |
| 121 | + |
| 122 | +Possiamo vincolare un componente ad avere tutte le action senza specificarne nessuna: |
| 123 | + |
| 124 | +``` js |
| 125 | +import * as actions from './actions' |
| 126 | + |
| 127 | +const vm = new Vue({ |
| 128 | + vuex: { |
| 129 | + getters: { ... }, |
| 130 | + actions // il componente ora accede a tutte le action |
| 131 | + } |
| 132 | +}) |
| 133 | +``` |
0 commit comments