The Power of Vue 3 Function Refs - Part 1

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

Really interesting and fascinating pattern!

👍︎︎ 5 👤︎︎ u/RinoDrummer 📅︎︎ Nov 30 2021 🗫︎ replies

Good to know about this.

But I'd rather use a parameter. Template refs are already obscure enough.

👍︎︎ 3 👤︎︎ u/anothermonth 📅︎︎ Nov 30 2021 🗫︎ replies

Great video, I learned something new :-)

With this pattern, is it somehow possible to use multiple "hooks"? For instance, useDimension('width'), useAnimate('wiggle'), useXXX()?

It seems like it is only possible to use one "hook" because the template element has just one :ref="element" to assign it to an element, right?

👍︎︎ 3 👤︎︎ u/connie-reynhart 📅︎︎ Nov 30 2021 🗫︎ replies

Good pattern, thanks.

👍︎︎ 2 👤︎︎ u/zrooda 📅︎︎ Nov 30 2021 🗫︎ replies

Since you are using typescript i would recommend using strongly type version.

const element = ref<HTMLElement>();

or even better

const element = ref<HTMLDivElement>();

👍︎︎ 2 👤︎︎ u/gevorgter 📅︎︎ Nov 30 2021 🗫︎ replies

This is pretty cool

👍︎︎ 2 👤︎︎ u/Miniotta 📅︎︎ Dec 02 2021 🗫︎ replies

Well done video!

Although I found by the time we were getting to function refs that it was far too much magic.

It's not obvious how the element ref is being passed to the Observer to use.

👍︎︎ 1 👤︎︎ u/Proud-Masterpiece 📅︎︎ Nov 30 2021 🗫︎ replies

This is neat. Although I agree with other poster it probably is easier to let consumers pass in the element ref. Easier if multiple composition functions would use the same ref too. Thanks for the video OP. It was clear and well explained!

👍︎︎ 1 👤︎︎ u/danyiwu 📅︎︎ Nov 30 2021 🗫︎ replies

I am confused why you used shallowRef?

It seems to me it causes nothing but an in-convivence of having to use .value with it. Since it becomes scoped variable for your lambda functions it will be alive till your component destroyed.

You said you like it but it's basically saying "i like wasting cpu time to do something not needed"

👍︎︎ 1 👤︎︎ u/gevorgter 📅︎︎ Nov 30 2021 🗫︎ replies
Captions
so i want to introduce you today to one of my favorite view three features and that's called function refs but before we talk about those they are a subcategory of something called template ref so let's explain what those are first and then talk about function reps and when and why they're useful so a template ref in view 3 is just a way of getting access to one of the elements in your template so that you can use it in your setup function and kind of the normal idiomatic way to do this is let's jump down to the script and take a look there so we have we import ref from the composition api and we just set up a blank ref we say const element equals ref um you can put null in here i think that's what the docs show and that's what i've seen around other people's code but it's not 100 necessary you can just leave that blank um so this ref since we're using script setup this element variable becomes available to the template and what i do here is in my div i set the ref attribute to the string element and just with those two pieces together the setting up the ref here and setting it as the ref attribute here view will know that once this component is mounted it should grab this div element and set it as the value of that ref so that when i call on mounted i can access element.value and i can be confident that this is going to be that div so why would we want to do that well in this case this is kind of a contrived case but i am doing something here with the resize observer so i've set up the resize observer so that i can move this element around and the width is going to get logged out basically in the inside the element there as its text content um you can't do this from the view template it'd be cool if you could do like at resize or something but as far as i know you can't do that you can only do the stuff with dom elements like click or key down so for resize observers intersection observers stuff like that we need to get access to this element in our setup function then down here we can set up our observer so ignore this piece for now i'm going to touch on that in just a sec but let's look at what happens in the on mounted hook because remember we can only access this div after the component has been mounted so inside the unmounted hook we are setting up our new resize observer and the callback that we want to happen there is whenever the observer fires it's going to give us a list of entries we're going to take the most recent entry and we're going to take the contentrec.width and we're going to set that as the value of text content on our div and then once we have that observer constructed we say observer.value.observe and we're going to pass in the element that we want to observe which again is the value of this reactive reference here so why are we using this shallow ref thing well when the component unmounts we actually want to clean up this observer and get rid of it we want to do observer.value.disconnect the browser is usually pretty good about garbage collecting this stuff for you but it's always just best practice to clean up event listeners and observers and things like that uh just to avoid memory leaks so uh my preferred way to do this is to set up a shallow ref which is just like a non-reactive proxy object and then you can just update the value mutate the value at any time this doesn't trigger any other reactive side effects or anything you can't watch a shallow ref you can't do anything like that it's just a nice convenient place to store data i could also just do something like let observer here and then i can just say observer equals and then i could just access it that way but it's just my preference to have you know like things that are going to be around for the full life so i go of a component i kind of like to have them stored as refs so i just use shallow ref there and then even though i'm creating it in scope here i can store it outside and from the on before on mount hook i can access that and disconnect it okay so that is the basic functionality um and so let's look at what happens when we want to move this into a composition function so that we can reuse it in another place so i've got a file set up here already it's called use dimension that's what we're going to call it so um let's move all these imports over and put them there oops and we want to take all this code and just get it all out of our script setup and put it into our use dimension function and then in here we'll say import use dimension use dimension [Music] and then uh we would do something you know just like use dimension we would just call a function this isn't going to work right now and that is because we've kind of lost this connection here when we have this ref set to element that's relying on the variable element being in scope of this function and it's no longer in scope there it's tucked away inside the use dimension function so if i save all this uh that should break everything yeah we're no longer getting the width logged in here that's totally broken um so a few different solutions we could do here i think the most obvious one um certainly the one that occurred to me first when i found this problem and i think the one that most people reach for is instead of creating this ref in here we just accept it as a parameter we just say that's the element and we just imagine that that is a i'm not going to do all the type annotations but we imagine that that's a reactive reference to an html element and then out here we would then import ref from view again and we would say const element equals just a blank ref and then pass it in here and that should get us working again yes we're all set um so a few things i don't like about this one it makes the developer who's using my function it it forces this additional step on them it makes them set up the ref first before they use my function so it's a little bit of extra work and of course they always have to attach that here the other thing that i don't like is just the way that it clutters up the parameters of this function like you can imagine we would do something like add a dimension option here which is a string and we could just say like arbitrarily any property and maybe we default that to width so that the function still works just like normal but we could customize that to say i actually want to log out the height and now we're getting the height instead of the width um so you can see that we've got this like we've you know we've got a we've got some required parameters some optional and with more complex functions of course this would get even more complicated um you can always cram this stuff into different objects and you know so that you don't actually have to remember the order of everything but still um it's just kind of messy to have all the stuff and have a mixture of required and optional stuff it's just difficult to remember and difficult to work with when you are using someone else's composition function for the first time so ideally we just have used dimension and have the dimension option there so we can customize that um and then we would get rid of this and then of course we're back to the same problem which is you know we don't have access to this anymore so this is where function refs come into play and before i show you how that solves this problem let's just look at what a function ref is and how it actually works so what we can do here is we can define one we're just going to say function ref equals l and then so we need to do something so a function ref is just a function that accepts only an element as its only argument and then it stores that element in some reactive reference so we can say constant element equals ref function graph equals element dot value equals l and then what we do with this instead of bind instead of passing the string as this ref we can actually bind our function to it um and i'll even actually log this out so that we can see more clearly that it's working so we've got the function ref set up there this actually should no maybe we're not working there um oh yeah because we don't have access to it here so let's get rid of the use dimension stuff for now and let's just focus on this console logging so i'm going to click over to this tab where we have the um the page open here and the console opens so you can see already we're getting this logged out so clearly our function ref has been called which is cool because it proves that this works we bind the function to the ref attribute um you can't do it like this you have to actually have it bound because you're passing in a function and not just a plain string and then you can do whatever you want with that element what you would normally do is you would just store it in a reactive reference so now what we can do is we can take this code uncomment these things and move this in here and we can say [Music] we can assume now that this is all working we'll get rid of this log and we can return the function ref and now we can say const function ref equals use dimension and that all now should be working let's see um yes yes have all that done maybe if i reload the page here yes okay so we're good so we're logging in yeah because we've customized it to use height the height is now being logged um so this really is a super cool pattern this idea of creating reactive references um and just kind of trusting that that element will be there when you need it on the mounted hook and then returning a function ref so that somebody can use it and bind it um so let's just we would maybe just call this element to keep that simpler or something and maybe this would be the idiomatic way that we tell people to use our composition function and now they can of course customize this if they want to use width instead of height and all of that works and we've got a really cool interesting smooth api here so we just call the function get a function ref back bind it where it needs to go it's just those two steps and everything else works and you can do really incredible things with this pattern you can set up all kinds of area attribute binding and custom event listeners and stuff because now that you have access to this element inside your composition function you can use all the familiar web apis dom apis anything you want um you know as long as you're calling it in the right lifecycle hooks and you're cleaning things up properly and you're timing your effects properly you can abstract really tons of different functionality into just nicely packaged little composition functions with clean um optional arguments and just make everything work really smoothly and it's it's a great developer experience when you're using this stuff and it's a really fun authoring experience as well to kind of have that power and in a lot of ways return to um sort of like basset back to the basics javascript where you're interacting with the same tools that you've always used using view reactivity and view patterns when you need them when they support your work and otherwise just kind of writing free form javascript and doing whatever you need to do so um super fun feature function refs are awesome i'm going to make another video where we talk about how to use this with lists of items things that are rendered by a v4 because that's really i think what vue intends function refs to be used for and that's kind of what they've documented as well so we're going to look at that and how that works but we'll do that in another video and so i'll catch you in the next one
Info
Channel: Alex Vipond
Views: 1,539
Rating: undefined out of 5
Keywords:
Id: EiqwYep8QEA
Channel Id: undefined
Length: 12min 28sec (748 seconds)
Published: Wed Oct 27 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.