/*
https://vueschool.io/articles/vuejs-tutorials/what-is-a-vue-js-composable/
*/
/*
Clarity of Data/Methods Source
Mixins = Data Source Obscured
Composables = Transparent Source of Data and Functions
*/
//MyComponent.vue
import ProductMixin from './ProductMixin'
import BrandMixin from './BrandMixin'
import UserMixin from './UserMixin'
export default{
mixins:[ProductMixin, BrandMixin, UserMixin],
created(){
// Where in the world did name come from?
// Let me look through each of the registered mixins to find out
// Oh man, it's not in any of them...
// It must be from a globally registered mixin
console.log(this.site)
// Oh, I got lucky here turns out the first mixin I inspected has the name
console.log(this.name)
}
}
//MyComponent.vue
import useProduct from './useProduct'
import useBrand from './useBrand'
import useUser from './useUser'
export default{
setup(){
const { name } = useProduct()
return { name }
}
created(){
// Where in the world did name come from?
// ah, it's not in setup anywhere... this doesn't exist and is an error
console.log(this.site)
// Oh, nice I can see directly in setup this came from useProduct
console.log(this.name)
}
}
/*
Naming Collisions
Mixins = Risk of Naming Collisions
Composables = NO risk of naming collisions
*/
//MyComponent.vue
import ProductMixin from './ProductMixin' // name = AirMax
import BrandMixin from './BrandMixin' // name = Nike
import UserMixin from './UserMixin' // name = John Doe
export default{
mixins:[ProductMixin, BrandMixin, UserMixin],
created(){
// Actually I'm not so lucky,
// yeah I found the name in ProductMixin
// but turns out UserMixin had a name too
console.log(this.name) // John Doe
}
}
//MyComponent.vue
import useProduct from './useProduct' // name = AirMax
import useBrand from './useBrand' // name = Nike
import useUser from './useUser' // name = John Doe
export default{
setup(){
const { name: productName } = useProduct()
const { name: brandName } = useBrand()
const { name: userName } = useUser()
return { productName, brandName, userName }
}
created(){
// Yay! Nothing is lost and I can get the name of each of the things
// together in my component but when writing the composables
// I don't have to think at all about what variable names might collide
// with names in other composables
console.log(this.productName)
console.log(this.brandName)
console.log(this.userName)
}
}
/*
Mutating Module's Reactive Data from the Component
Mixins = Can NOT Safeguard Own Reactive Data
Composables = Can Safeguard Own Reactive Data
*/
// RequestMixin.js
export default {
data(){
return {
loading: false,
payload: null
}
},
methods:{
async makeRequest(url){
this.loading = true
const res = await fetch(url)
this.payload = await res.json()
this.loading = false
}
}
}
// useRequest.js
import { readonly, ref } from "vue";
export default () => {
// data
const loading = ref(false);
const payload = ref(null);
// methods
const makeRequest = async (url) => {
loading.value = true;
const res = await fetch(url);
payload.value = await res.json();
};
// exposed
return {
payload: readonly(payload), //notice the readonly here
loading: readonly(loading), // and here
makeRequest
};
};
/*
Global State with Composables
*/
//CounterMixins.js
export default{
data(){
return { count: 0 }
},
methods:{
increment(){
this.count ++
}
}
}
//useCounter.js
import {ref, readonly} from 'vue'
export default () => {
const count = ref(0)
const increment = ()=> count.value++
return {
count: readonly(count),
increment
}
}
//useCounter.js
import {ref, readonly} from 'vue'
const count = ref(0)
export default () => {
const increment = ()=> count.value++
return {
count: readonly(count),
increment
}
}