Skip to content

PresenterFactory ​

The factory function is used to create a presenter hook for a Vue component.

presenterFactory() ​

Type ​

ts
function presenterFactory(callback: (props: object | void, view: object | void) => PresenterConfig): PresenterHook

Example ​

ts
import { computed } from 'vue'
import { presenterFactory } from 'model-vue-presenter'

type Props = void
type View = void

const usePresenter = presenterFactory((props, view) => {
  return {
    viewModel: computed(() => ({
      // ...
    })),

    onCreated() {},
    onDestroy() {},
  }
})

viewModel ​

The presenter configuration callback must return a viewModel.

The viewModel property must be a Vue computed property.

Type ​

ts
type ViewModel = ComputedRef<Record<string, unknown>>

Example ​

ts
export const usePresenter = presenterFactory(() => {
  return {
    viewModel: computed(() => ({
      heading: 'Hello world'
    })),
  }
})

mockViewModel() ​

You can mock a presenter view model. Useful for mocking components in Storybook.

The new returned viewModel must contain the same properties as the original viewModel.

The presenter will throw an error if the viewModel doesn't contain all the required properties.

Type ​

ts
function mockViewModel(): ViewModel

Example ​

Here we are mocking a viewModel's skeleton loader and heading state. Ideal for showing a specific component in a "loading" state in Storybook for example.

ts
usePresenter.mockViewModel((viewModel) => {
  return {
    ...viewModel,
    isSkeletonLoaderShown: true,
    heading: 'My overwritten heading text',
  }
})

props and view references ​

You can optionally pass Vue component props and/or view references.

Type ​

ts
type Props = Record<string, unknown>
ts
type View = Record<string, unknown>

INFO

Make sure you don't destructure props in your Vue component as they will lose reactivity. You must always pass the entire props object to the presenter.

Example ​

ts
export const usePresenter = presenterFactory((props, view) => {
  return {
    viewModel: computed(() => ({
      heading: 'Hello world'
    })),
  }
})
vue
<script setup lang="ts">
const props = defineProps()

const viewReferences = {
  someFunction: () => {}
}
  
const { viewModel, presenter } = usePresenter(props, viewReferences) 
</script>

onCreated() ​

The presenter has an optional internal lifecycle hook which is called when the related Vue component is created.

INFO

The onCreated hook must be synchronous. Vue will not clean up reactive watchers if they are created asynchronously. See the official Vue documentation for more info.

Type ​

ts
function onCreated(): void

Example ​

ts
export const usePresenter = presenterFactory((props, view) => {
  return {
    // ...
    onCreated() {
      // Logic to be executed when the component is created.
    }
  }
})

onDestroy() ​

The presenter has an optional internal lifecycle hook which is called when the related Vue component is destroyed.

Type ​

ts
function onDestroy(): void

Example ​

ts
export const usePresenter = presenterFactory((props, view) => {
  return {
    // ...
    onDestroy() {
      // Logic to be executed when the component is destroyed.
    }
  }
})

spy() ​

You can spy on a presenter instance. This is useful during unit and integration testing.

Type ​

ts
function spy(): PresenterHook

Example ​

Here's an example where we spy on the presenter instance in order to write assertions against the viewModel.

The Vue component instance will interact with the presenter, but you can still get read access to the viewModel by using the spy() function.

ts
import waitForExpect from "wait-for-expect";

it('loads some products data when clicking the button', async () => {
  const wrapper = mount(component)
  
  const { viewModel } = usePresenter.spy()

  // Idle state
  expect(viewModel.value.products.length).toBeFalsy()

  // Click the button
  wrapper.find('button').trigger('click')
  
  await waitForExpect(() => {
    expect(viewModel.value.products.length > 10).toBeTruthy()
  })
})