Created
November 7, 2020 00:18
-
-
Save lmiller1990/48c4fd841b67eaa4f226011f70351daf to your computer and use it in GitHub Desktop.
Renderless Components
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<v-input | |
v-slot="{ error }" | |
:min="5" | |
:max="10" | |
:value="username" | |
:validation-algorthm | |
> | |
<input v-model="username" /> | |
<div v-if="error" class="error"> | |
{{ error }} | |
</div> | |
</v-input> | |
</template> | |
<script> | |
import { ref } from 'vue' | |
import VInput from './v-input.vue' | |
export default { | |
components: { VInput }, | |
setup() { | |
return { | |
username: ref('') | |
} | |
} | |
} | |
</script> | |
<style> | |
.error { color: red; } | |
</style> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<script> | |
function getError(value, { min, max }) { | |
if (!value) { | |
return 'Required' | |
} | |
if (value.length < min) { | |
return `Min is ${min}` | |
} | |
if (value.length > max) { | |
return `Max is ${max}` | |
} | |
} | |
import { computed } from 'vue' | |
export default { | |
props: ['min', 'max', 'value'], | |
setup(props, ctx) { | |
const error = computed(() => getError( | |
props.value, | |
{ min: props.min, max: props.max } | |
)) | |
return () => ctx.slots.default({ | |
error: error.value | |
}) | |
} | |
} | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Interesting question @bviala. I think it's more or less the same thing - reusability via composables vs reusability via components. This pattern is probably less useful with the introduction of composables, as opposed to Vue 2 which did not have such a concept.
Perhaps a better example would be something like a multiselect component. You want to support:
A simple implementation might be like this:
You also might want to allow the developer to fully customize the markup and appearance of the dropdown and options. This is the problem renderless components solve. It would look something like this:
This is quite a bit more awkward to solve using a composable. How would you handle this? I didn't think about it too much in depth, there might be some nice way to do it with a composable, but this is the general problem renderless components solved, at least in Vue 2 before we had composables - customized markup while abstracting the implementation details.
I'd be interested in seeing a composable
useMultiselect
implementation. It's possible renderless components are not as useful now that we have composables. What do you think?