By using component-based technologies such as Vue.js, doesn't mean that all components must be UI based.

In fact, my favourite way to apply advanced reusability in large applications is by using component composition.

With scoped slots, as you haven seen in "Using scoped slots in Vue.js", you can encapsulate logic in another component and pass it to a slot via props. That allows you to compose the UI and behaviour of a new component by combining multiple of them.

Today, I'm going to show you a Data provider Component example.

Data Provider is a renderless component, meaning that it doesn't need to render anything.

The base to create a renderless component is to create a scoped slot from a render function and pass any prop to it:

render() { return this .$scopedSlots.default({ loading : ! this .loaded, data : this .data }); }

Due to an inconsistency on scoped slots (fixed by version 2.6), you can better do it like this to make it work in any case:

render() { const slot = this .$scopedSlots.default({ loading : ! this .loaded, data : this .data }); return Array .isArray(slot) ? slot[ 0 ] : slot; }

Knowing that, to create a Data Provider component you must perform an ajax/fetch call when the component is created, and then pass that data to the scoped slot.

A final version of DataProvider.js could be:

import axios from "axios" ; export default { props : [ "url" ], data : () => ({ data : null , loaded : false }), created() { axios.get( this .url).then( ( { data } ) => { this .data = data; this .loaded = true ; }); }, render() { const slot = this .$scopedSlots.default({ loading : ! this .loaded, data : this .data }); return Array .isArray(slot) ? slot[ 0 ] : slot; } };

Notice that it's a .js file. Since it just has the script part of the component, it doesn't need to be a .vue file.

The Data Provider component also is holding a loading state, so you can use that to render different UI depending on that state. An example could be:

< template > < DataProvider url = "https://jsonplaceholder.typicode.com/users" > < div v-slot = "{ data, loading }" > < div v-if = "loading" > Loading... </ div > < div v-else > < h2 > Result: {{ data.length }} users </ h2 > < p v-for = "user in data" :key = "user.id" > {{ user.name }} </ p > </ div > </ div > </ DataProvider > </ template >

That's it!

If you want to check this example running, go to this CodeSandbox!

Don't forget to share VueDose with your colleagues, so they also know about these tips as well!

See you next week.

Alex