Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Business logic in Vue.js

Business logic in Vue.js

Sobolev Nikita

August 22, 2019
Tweet

More Decks by Sobolev Nikita

Other Decks in Programming

Transcript

  1. export default { data () { return { username: ''

    } }, template: ` <button click="loadUser">Hello {{ username }}</button> `, loadUser () { this.username = this.$axios.get('...').data }, } !7
  2. export default { data () { return { username: ''

    } }, template: ` <button click="loadUser">Hello {{ username }}</button> `, loadUser () { this.username = this.$axios.get('...').data }, } !9
  3. export default { data () { return { username: ''

    } }, template: ` <button click="loadUser">Hello {{ username }}</button> `, loadUser () { this.username = this.$axios.get('...').data }, } !10
  4. export default { data () { return { username: ''

    } }, template: ` <button click="loadUser">Hello {{ username }}</button> `, loadUser () { this.username = localStorage.getItem('user') }, } !15
  5. export default { // ... props: ['callback'], loadUser () {

    this.username = this.callback(...) }, } !17
  6. Вопросики • А если у нас нет возможности передать callback?

    • А если очень глубокая вложенность? !18
  7. export default { // ... props: ['http'], loadUser () {

    if (this.http) { this.username = this.$axios.get(...) } else { this.username = localStorage(...) } }, } !21
  8. Вопросики • А если поведений много? • А если у

    нас нет возможности выставить флаг? • А если очень глубокая вложенность? • А как его тестировать? !22
  9. import { mount, createLocalVue } from '@vue/test-utils' import MockAdapter from

    'axios-mock-adapter' import MyComponent from '~/components/MyComponent' const localVue = createLocalVue() describe('unit tests for MyComponent', () => { test('should have correct logic', () => { const wrapper = mount(MyComponent, { localVue }) new MockAdapter(wrapper.axios) .onGet('...') .reply(200, ['sobolevn']) wrapper.loadUser() expect(wrapper.username).toBe('sobolevn') }) }) !24
  10. import { mount, createLocalVue } from '@vue/test-utils' import MyComponent from

    '~/components/MyComponent' const localVue = createLocalVue() describe('unit tests for MyComponent', () => { test('should have correct logic', () => { const wrapper = mount(MyComponent, { localVue, provide: { buttonCallback: () => 'sobolevn' }, }) wrapper.loadUser() expect(wrapper.username).toBe('sobolevn') }) }) !28
  11. export default { data () { return { username: ''

    } }, template: ` <button click="loadUser">Hello {{ username }}</button> `, inject: ['buttonCallback'], loadUser () { this.username = this.buttonCallback() }, } !30
  12. export default { provide: { buttonCallback: () => this.$axios.get('...'), },

    components: { MyComponent }, template: `<MyComponent />`, } !32
  13. Плохие решения • Пихать логику в компоненты • Делать вид,

    что ты не пихаешь логику в компоненты !33
  14. import buttonCallbackFactory from 'logic/http' export default { provide: { buttonCallback:

    buttonCallbackFactory(...), }, components: { MyComponent }, template: `<MyComponent />`, } !35
  15. import { Inject, Injectable } from 'vue-typedi' import { Action

    } from 'vuex-simple' @Injectable() export default class UsernameModule { @Inject(tokens.USERNAME_SERVICE) public service // type: UsernameServiceProtocol @Action() public async fetchUsername () { const username = await this.service.fetchUsername() // ... } } !41
  16. И не только DI • Higher Order Components • Slots,

    Named Slots • https://github.com/vuejs/vue-function-api • Event Bus • Vue.observable, https://github.com/vuejs/vue-rx !45
  17. Полезные ссылки • https://guide.elm-lang.org/architecture/ • https://markus.oberlehner.net/blog • https://blog.ploeh.dk/2016/03/18/functional- architecture-is-ports-and-adapters/ •

    https://fsharpforfunandprofit.com/rop/ • https://www.destroyallsoftware.com/screencasts/ catalog/functional-core-imperative-shell • https://sobolevn.me/ !49