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

Business logic in Vue.js

Business logic in Vue.js

Avatar for Sobolev Nikita

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