Vue === WORK IN PROGRESS: a Vue pattern for a component to edit the properties of some object ------------------------------------------------------------------------------------- This is never going to be finished. I do not use Vue anymore. .. contents:: Usage:: Minimal implementation:: It is careful not to ever modify the value passed to it. The parent expects that it can manage changes itself by using a computed property or watcher if it wants. The component emits events to tell the parent when the user has chosen to save their changes, or cancel, but leaves it to the parent to do what it wants at that point. Example using the component:: Reactivity ---------- The following applies to the store's state, anything in a component's *data*, and other things that get pulled into the reactivity system. When an object is added to Vue's reactivity system, Vue replaces all its properties with getters and setters under the covers, so that if you fetch the value of a property, or assign a new value to it, Vue is aware and can react. (``_) However, for technical reasons, Vue cannot detect when a property is added to or removed from an object. (``_) **The implications are:** * When updating the store, it's fine to assign a new value to a property of the *state*. * When updating component data, it's fine to assign a new value to a property of the component *data*. * Don't try to use Object.assign or equivalent to update properties of objects in-place in the store???? It doesn't seem to work. Component properties -------------------- Vue doesn't necessarily rebuild a component from scratch when one of its properties changes. If you're using a property to initialize something, for example, you will need to `watch` that property and re-initialize when it changes that way. *However,* I'm not sure even watching a property works. I've seen components updated when a watch on a property never triggered. Vuex (the store) ---------------- Getters ....... `Getters doc `_ Getters provide computed values based on the state. Their results are cached until the state they depend on changes. Getters are accessed as *properties* not *methods*. They are passed as a second arg an object with all the store's getters, in case they want to use them. :: const store = new Vuex.Store({ ... getters: { totalCost: (state, othergetters) => { return some_computation_on_state } // component... computed: { the_total_cost () { return store.getters.totalCost // No parens, not called like a method } } Mutations ......... `Mutations doc `_ Mutations *must be synchronous*. They cannot be called. They must be invoked using ``commit``. They receive a state and optional arguments, and can change the state. When the state changes, other Vue components observing the state will update automatically. Any value returned by a mutation is *not* passed back to the caller of ``commit``. Actions ....... `Actions doc `_ Actions can contain asynchronous code. They receive a ``context`` object that has methods like ``commit`` and properties like ``state`` and ``getters``. Actions cannot be called. They must be invoked using ``dispatch``. Any value returned by an action is passed back to the caller of ``dispatch``, by way of resolving the promise that dispatch returns to that value. Dispatching actions always returns Promises. Example:: const store = new Vuex.Store({ state: { count: 0 }, mutations: { increment (state) { state.count++ } }, actions: { increment (context) { context.commit('increment') }, checkout ({ commit, state }, products) { // save the items currently in the cart const savedCartItems = [...state.cart.added] // send out checkout request, and optimistically // clear the cart commit(types.CHECKOUT_REQUEST) // the shop API accepts a success callback and a failure callback shop.buyProducts( products, // handle success () => commit(types.CHECKOUT_SUCCESS), // handle failure () => commit(types.CHECKOUT_FAILURE, savedCartItems) ) }, async actionA ({ commit }) { commit('gotData', await getData()) }, async actionB ({ dispatch, commit }) { await dispatch('actionA') // wait for `actionA` to finish commit('gotOtherData', await getOtherData()) } } }) Custom components implementing v-model -------------------------------------- Vue handles the heavy lifting when a component is included somewhere with a v-model attribute. All your component needs to do is accept a "value" property, and emit an "input" event when the value changes, with the new value. Possibly surprising things in Vue ================================= The Vue documentation tells you how almost everything in Vue works, but you really need to know more than that to use Vue. I like the analogy that knowing how to drive nails and saw boards doesn't enable you to build a house, especially not a house that won't fall down. Here are some things I've discovered through experience, or that were mentioned in the documentation but I've found to be more important than I would have guessed. .vue files ---------- * You can start your ``.vue`` file with a big multiline ```` comment to document it. Templates --------- * A component must end up rendering either zero or one HTML element. It may, of course, have lots of stuff nested inside. The real surprise to me was that it can render to no element at all. * You can use both ``:class`` and ``class`` on the same element. The resulting classes will be merged. * When using 'v-if', 'v-else', 'v-else-if' in templates, give each element using them a unique key, just as if they were using 'v-for'. * "control-flow" features like 'v-if' and 'v-for' can only be used as attributes on HTML elements. But if you really don't want an HTML element there, you can put them on the pseudo-element ``