Vue.js techtalk: Advanced

Vue.js techtalk: Advanced

Let's talk about how to get Router and Vuex data store working for a simple app - API Inspector

0f3a2fe881c742a4dbb5afef5a8f5c0e?s=128

Jakub Mikulas

February 23, 2017
Tweet

Transcript

  1. Vue.js Advanced: Router & Vuex

  2. In previous episodes…

  3. Warning Code incoming! And it could be a bumpy ride.

  4. Let's create this badboy

  5. None
  6. We have the basic scheme • 2 columns • le,

    one with naviga4on is always visible => it'll be our skeleton • right one will be changing depending on what we want to see => we will need a router • Empty state is our default, because we don't have anything to show now
  7. Init the project with vue-cli and you are ready

  8. Let's get the basic skeleton - 2 columns in CSS

  9. Put the basics in a single file

  10. Something that won't be always visible, empty state, gets its

    own component
  11. Router is serving just this one empty state

  12. Vue devtools are opera.onal at this stage

  13. Let's add something to the le0 • I'm not limited

    by any exis2ng API, so I can do whatever I want now • It will be a list of recent calls => array • we don't have much choice how to render list => v-for="call in calls" to iterate
  14. None
  15. Create a JSON with some dummy data and import it

    { "method": "get", "resourceName": "Something good", "responseCode": 200 },
  16. // App.vue import calls from './calls.json'; export default { name:

    'inspector', data() { return calls; }, }; In template: <div class="aside__list"> <div v-for="call in calls">{{call.resourceName}}</div> </div>
  17. // App.vue import calls from './calls.json'; export default { name:

    'inspector', data() { return calls; }, }; In template: <div class="aside__list"> <!-- This sucks --> <div v-for="call in calls">{{call.resourceName}}</div> </div>
  18. <!-- call.vue --> <template> <div class="call"> <div class="call__nameWrap"> <div class="call__name">{{call.resourceName}}</div>

    <div class="call__meta">Code: <strong>{{call.responseCode}}</strong></div> </div> <div class="call__method" :class="'call__method--' + call.method">{{call.method}}</div> <div class="call__arrow"></div> </div> </template> <script> export default { name: 'call', props: { call: Object, }, }; </script>
  19. // App.vue import call from './components/call'; // Import the component

    import calls from './calls.json'; export default { name: 'inspector', data() { return calls; }, components: { call, // Register the component }, }; In template: <div class="aside__list"> <call v-for="call in calls" /> </div>
  20. <!-- call.vue --> <template> <div class="call"> <div class="call__nameWrap"> <div class="call__name">{{call.resourceName}}</div>

    <div class="call__meta">Code: <strong>{{call.responseCode}}</strong></div> </div> <div class="call__method" :class="'call__method--' + call.method">{{call.method}}</div> <div class="call__arrow"></div> </div> </template> <script> export default { name: 'call', props: { call: Object, }, }; </script>
  21. // App.vue import call from './components/call'; // Import the component

    import calls from './calls.json'; export default { name: 'inspector', data() { return calls; }, components: { call, // Register the component }, }; In template: <div class="aside__list"> <call v-for="call in calls" :call="call" /> </div>
  22. None
  23. Let's make the le, naviga1on working • we need some

    iden+fier for links, so I've added id to the calls.json • let's use standard <router-link> which transforms into standard <a> (so "Open in a new panel" works in your browser) <!-- components/call.vue --> <div class="call"> <!-- from this --> <router-link class="call" :to="{ name: 'Call', params: { id: call.id } }"> <!-- ... --> </router-link>
  24. // router.js export default new Router({ routes: [ { path:

    '/', name: 'Empty', component: empty, }, { path: '/call/:id', name: 'Call', component: callDetail, <!-- new component --> }, ], });
  25. None
  26. Now let's get the selected data from the le2 to

    the right part it's a good *me to use Vuex Vuex is a state management pa.ern + library
  27. Think about it as something that will take away the

    guess work from frontend. It's right there in Vue Devtools
  28. Step 1: create a store and move the sta2c array

    of calls to Vuex // store.js import Vue from 'vue'; import Vuex from 'vuex'; import calls from './calls.json'; Vue.use(Vuex); // Initialize export default new Vuex.Store({ state: { calls, }, });
  29. Step 2: Connect Vuex store to the app // main.js

    import Vue from 'vue'; import App from './App'; import store from './store'; import router from './router'; new Vue({ el: '#app', router, store, // Add Vuex store to the app template: '<App/>', components: { App }, });
  30. Step 3: get reac,ve data from the store // App.vue

    import call from './components/call'; import calls from './calls.json'; export default { name: 'inspector', data() { return calls; }, components: { call, }, };
  31. Step 3: get reac,ve data from the store // App.vue

    import call from './components/call'; export default { name: 'inspector', computed: { calls() { return this.$store.state.calls; }, }, components: { call, }, };
  32. This image might be too complicated But takeaway is that

    important bits are happening in Vuex
  33. Components can't write to the state! They can only issue

    orders to the store. Like: "do this ac6on" or "do this ac6on, with this value" Components are just saying eg.: • User did something, go fetch new data • User did something, change your data
  34. Vuex store have 4 main parts: • state: that's just

    serializable Object of current state • ge&ers: read-only helpers that can transform value (eg. filter an array). They get their data from read-only state. Example coming up. • muta*ons: only way to write to the state. Simple synchronous funcFons that can modify the state. • ac*ons: larger, possibly asynchronous or chained funcFons, that can start a mutaFon. Imagine AJAX call, that on success passes data to the mutaFon to do the state write.
  35. Let's create a ge+er that we can use to get

    data to the right side. Why ge#er? Because its value is changing depending on state of the applica6on (different routes will want to see different data on the right)
  36. Let's do it by saving current route to Vuex. We

    could do it manually, by crea:ng muta:ons, but there is an official helper vuex- router-sync. This adds current route Object to Vuex state. // main.js import Vue from 'vue'; import { sync } from 'vuex-router-sync'; // import the package import App from './App'; import store from './store'; import router from './router'; sync(store, router); // sync Store with Router, done new Vue({ el: '#app', router, store, template: '<App/>', components: { App }, });
  37. // store.js import Vue from 'vue'; import Vuex from 'vuex';

    import calls from './calls.json'; Vue.use(Vuex); export default new Vuex.Store({ state: { calls, showExample: false, }, getters: { activeCall: state => state.calls.find(c => c.id === state.route.params.id), }, });
  38. export default { name: 'callDetail', computed: { call() { return

    this.$store.getters.activeCall; }, }, };
  39. None
  40. Recap • Router is just a plain Object • Vuex

    store is just a plain Object - ge7ers, muta:ons and ac:ons are just simple func:ons => it's simple to test • Vuex improves controller readability