export default {
  data () {
    return {
      searchText: '',
    }
  },
  
  computed: {
    filteredItems () {
      // ...
    },
  },
}Search ▶
Search ▶
export default {
  data () {
    return {
      searchText: '',
      sortBy: 'name',
    }
  },
  
  computed: {
    filteredItems () {
      // ...
    },
    
    sortedItems () {
      // ...
    },
  },
}Search ▶
Search ▶
Sort ▶
Sort ▶
Features are organized by component options
Organized by component options
Organized by features
export default {
  data () {
    return {
      searchText: '',
      sortBy: 'name',
    }
  },
  
  computed: {
    filteredItems () {
      // ...
    },
    
    sortedItems () {
      // ...
    },
  },
}Search ▶
Search ▶
Sort ▶
Sort ▶
Search ▶
Sort ▶
export default {
  setup () {
    // Search feature
    const searchText = ref('')
    const filteredItems = computed(() => /* ... */)
    
    // Sort feature
    const sortBy = ref('name')
    const sortedItems = computed(() => /* ... */)
  },
}Search ▶
Sort ▶
export default {
  setup () {
    // Search feature
    const searchText = ref('')
    const filteredItems = computed(() => /* ... */)
    
    // Sort feature
    const sortBy = ref('name')
    const sortedItems = computed(() => /* ... */)
  },
}Organized by feature
Search ▶
Sort ▶
export default {
  setup () {
    // Search feature
    const searchText = ref('')
    const filteredItems = computed(() => /* ... */)
    
    // Sort feature
    const sortBy = ref('name')
    const sortedItems = computed(() => /* ... */)
    return {
      searchText,
      sortBy,
      sortedItems,
    }
  },
}Search ▶
Sort ▶
export default {
  setup () {
    // Search feature
    const searchText = ref('')
    const filteredItems = computed(() => /* ... */)
    
    // Sort feature
    const sortBy = ref('name')
    const sortedItems = computed(() => /* ... */)
    return {
      searchText,
      sortBy,
      sortedItems,
    }
  },
}Expose to the template
Search ▶
Sort ▶
export default {
  setup () {
    const { searchText, filteredItems } = useSearch()
    const { sortBy, sortedItems } = useSort(filteredItems)
    return {
      searchText,
      sortBy,
      sortedItems,
    }
  },
}
// Search feature
function useSearch (items) {
  const searchText = ref('')
  const filteredItems = computed(() => /* ... */)
  return { searchText, filteredItems }
}
// Sort feature
function useSort (items) {
  const sortBy = ref('name')
  const sortedItems = computed(() => /* ... */)
  return { sortBy, sortedItems }
}Search ▶
Sort ▶
export default {
  setup () {
    const { searchText, filteredItems } = useSearch()
    const { sortBy, sortedItems } = useSort(filteredItems)
    return {
      searchText,
      sortBy,
      sortedItems,
    }
  },
}
// Search feature
function useSearch (items) {
  const searchText = ref('')
  const filteredItems = computed(() => /* ... */)
  return { searchText, filteredItems }
}
// Sort feature
function useSort (items) {
  const sortBy = ref('name')
  const sortedItems = computed(() => /* ... */)
  return { sortBy, sortedItems }
}Extract features into Composition Functions
export default {
  data () {
    return {
      searchText: '',
      sortBy: 'name',
    }
  },
  
  computed: {
    filteredItems () {
      // ...
    },
    
    sortedItems () {
      // ...
    },
  },
}const searchMixin = {
  data () {
    return { searchText: '' }
  },
  computed: {
    filteredItems () { /* ... */ },
  },
}
const sortMixin = {
  data () {
    return { sortBy: 'name' }
  },
  computed: {
    sortedItems () { /* ... */ },
  },
}
export default {
  mixins: [ searchMixin, sortMixin ],
}const searchMixin = {
  data () {
    return { searchText: '' }
  },
  computed: {
    filteredItems () { /* ... */ },
  },
}
const sortMixin = {
  data () {
    return { sortBy: 'name' }
  },
  computed: {
    sortedItems () { /* ... */ },
  },
}
export default {
  mixins: [ searchMixin, sortMixin ],
}function searchMixinFactory ({ ... }) {
  return {
    data () {
      return { searchText: '' }
    },
    computed: {
      filteredItems () { /* ... */ },
    },
  }
}
function sortMixinFactory ({ ... }) {
  return {
    data () {
      return { sortBy: 'name' }
    },
    computed: {
      sortedItems () { /* ... */ },
    },
  }
}
export default {
  mixins: [ searchMixinFactory(), sortMixinFactory() ],
}function searchMixinFactory ({ ... }) {
  return {
    data () {
      return { searchText: '' }
    },
    computed: {
      filteredItems () { /* ... */ },
    },
  }
}
function sortMixinFactory ({ ... }) {
  return {
    data () {
      return { sortBy: 'name' }
    },
    computed: {
      sortedItems () { /* ... */ },
    },
  }
}
export default {
  mixins: [ searchMixinFactory(), sortMixinFactory() ],
}<script>
export default {
  // Search feature here
}
</script>
<template>
  <div>
    <slot v-bind="{ searchText, filteredItems }" />
  </div>
</template><script>
export default {
  // Sort feature here
}
</script>
<template>
  <div>
    <slot v-bind="{ sortBy, sortedItems }" />
  </div>
</template><SearchService
  v-slot="searchProps"
>
  <SortService
    :item="searchProps.filteredItems"
    v-slot="sortProps"
  >
    <li v-for="item of sortProps.sortedItems">
      ...
    </li>
  </SearchService>
</SearchService>SearchService.vue
SortService.vue
<script>
export default {
  // Search feature here
}
</script>
<template>
  <div>
    <slot v-bind="{ searchText, filteredItems }" />
  </div>
</template><script>
export default {
  // Sort feature here
}
</script>
<template>
  <div>
    <slot v-bind="{ sortBy, sortedItems }" />
  </div>
</template><SearchService
  v-slot="searchProps"
>
  <SortService
    :item="searchProps.filteredItems"
    v-slot="sortProps"
  >
    <li v-for="item of sortProps.sortedItems">
      ...
    </li>
  </SearchService>
</SearchService>export default {
  data () {
    return {
      searchText: '',
      sortBy: 'name',
    }
  },
  
  computed: {
    filteredItems () {
      // ...
    },
    
    sortedItems () {
      // ...
    },
  },
}export default {
  setup () {
    const { searchText, filteredItems } = useSearch()
    const { sortBy, sortedItems } = useSort(filteredItems)
    return {
      searchText,
      sortBy,
      sortedItems,
    }
  },
}
// Search feature
function useSearch (items) {
  const searchText = ref('')
  const filteredItems = computed(() => /* ... */)
  return { searchText, filteredItems }
}
// Sort feature
function useSort (items) {
  const sortBy = ref('name')
  const sortedItems = computed(() => /* ... */)
  return { sortBy, sortedItems }
}export default {
  setup () {
    const { searchText, filteredItems } = useSearch()
    const { sortBy, sortedItems } = useSort(filteredItems)
    return {
      searchText,
      sortBy,
      sortedItems,
    }
  },
}
// Search feature
function useSearch (items) {
  const searchText = ref('')
  const filteredItems = computed(() => /* ... */)
  return { searchText, filteredItems }
}
// Sort feature
function useSort (items) {
  const sortBy = ref('name')
  const sortedItems = computed(() => /* ... */)
  return { sortBy, sortedItems }
}Vue
Apollo Client
Node
GraphQL
Apollo Server