Placeholder Image

字幕表 動画を再生する

  • So, uh, like I said, my name's Tanner Lindsley from Utah.

  • And I love Java script so much.

  • Uh, I also love react even more.

  • I'm happy Thio be able to talk about react at a Java script conference.

  • I'm on get hub.

  • Probably way too much riding way too many open source libraries.

  • I'm also on Twitter and YouTube.

  • You come say hi to me there if you want.

  • Um, I know that you're all probably feeling like you can't see my screen.

  • Yeah, you're probably feeling a little bit like my son here, you know, just really tired and wanting to consume that last little bit of javascript on.

  • Just do your best.

  • You know that?

  • It's ah, I know it's hard, but we're gonna make it through it together.

  • Um, because today I'm talking about react, tooks and more specifically, custom react hooks.

  • And I'm so excited about this.

  • I hope you are too.

  • I know it's been a noisy year.

  • Um, you guys probably feel like, uh whether you're whether you love react or not, you probably feel this way.

  • So I'm gonna do my best today to make sure that this is not just another React Hopes tutorial.

  • It's going to be fast because I have a lot of content to go over and there's gonna be a lot of code.

  • Um, hopefully, it's a lot of fun.

  • I'm gonna be saying, used a lot, So it's hard.

  • It's a tongue twister, you'll see.

  • So before we get into, uh, my the bulk of my talk, let's go through react hooks basics really quickly.

  • Uh, classes are out.

  • We no longer write with classes.

  • Everything is just a function now.

  • And that is so nice.

  • It makes us so that components that used to look like this to use state don't have to look like that anymore.

  • We could just use you ST so much better, in my opinion, where we can use use reducer class life cycles are no longer a thing.

  • Oh, I'm so glad to be done with these things.

  • Um, also, we don't have to dio manual change detection anymore.

  • With the old class life cycles, we can just use the use of fact function from react, passes some dependencies and everything will just synchronize for us.

  • It also comes built in with memorization and computer state things around memorizing values and functions Where before what?

  • We could do this with react before, but now it's built in so we can make sure that we're only computing or doing work when we need to be doing it.

  • Uh and last.

  • The most important thing that I'd like to talk about today is custom hooks, which custom homes, really just a function that runs inside of a component that can run other hooks or other functions like you state used, reduce or whatever.

  • And they could be recursive.

  • They can go forever.

  • You can have, ah, custom put, calling other custom hood calling the custom hook.

  • Call another customer and everything will just come back in and it just works.

  • It's amazing.

  • It makes us so patterns like this that before we had to nest all these callbacks and create hired or components and render props and, you know, functions as Children.

  • All that gets to go away, and we're simply left with a couple of function calls that we can make inside of our inside of our components.

  • Custom hooks are so powerful, I believe that they give us a couple more afford Ince's that we didn't have when we were using class components.

  • Um, I think that they encourage us to build our own solutions because it makes building our own solutions easier.

  • The AP I is more expressive.

  • I I also believe that building hooks custom hooks way more portable and share a bowl than building custom components and trying to move logic around with components.

  • Another great thing is that custom hooks can be component, aware and abstract, essentially anything that we want them to just makes him very powerful for integrating with essentially anything we want to integrate with the outside in the outside world, away from react.

  • And last but not least, I think they highly encourage rapid adoration for some of the reasons that I'm gonna talk about today.

  • So the biggest reason that I believe that all those things were true is beat that hooks, Uh, with the introduction of custom hooks, I think that we're going to see or have already seen a return to components handling, user interface and hooks handling business logic.

  • And if this seems like a no brainer, you're ahead of the curve.

  • And if it doesn't, um, that's what I'd like to talk about today through so many migrations of old projects, two hooks going 100% hooks and new Greenfield projects where was able to experiment with new patterns around custom hooks and see, you know, how far can we push the limits of this new A.

  • P I I've discovered a couple of use cases that have really sparked new interests for me.

  • With this hooks A p I, um most of them around building portable you, I utilities.

  • Ah, few of them.

  • Well, actually a lot of them around Managing Global State and Server ST and also encapsulating business logic for our applications inside of these custom hooks.

  • And I want to share with you a couple of these use cases today to show you how custom hooks can really change the way that you think about writing your applications and to be more productive.

  • Why not start off with something that is so hot right now?

  • You can't ship a nap without it, and it's sometimes it's the first thing that we all think about.

  • Probably the most important thing we all think about as dark mode.

  • You can't ship without it, right?

  • This is so hard right now.

  • Everybody wants a dark mode.

  • You know, everybody's got that toggle at the top of their sight.

  • Go between light and dark mode.

  • Um, it's pretty easy to do.

  • You can just set up some state and toggle between with a function of set is dark to true or false.

  • It's really that easy.

  • I wanted something a little more sophisticated for my dark mouth.

  • I don't know if you guys have ever seen match media, but it's an A p I that you can use to match CSS media queries in JavaScript and detect certain things about the user's environment.

  • Right here we have a match me that's detecting whether the user prefers a light or a dark theme, and we can actually set up our state to start with.

  • That s so that if the user has a darker lightning preference on their device, are state now starts with that preference and they can toggle between it.

  • But who has this enabled on their computer?

  • It's auto mode ideo and I love it.

  • And I thought wouldn't it be amazing if we could make it so our light and dark themes would actually react to that automatic mode on our devices, turns out.

  • It's not too hard.

  • Weaken taken effect and put our match media inside it and listen to changes to that match media and update our dark variable whenever that changes.

  • And if we put all that together inside of our app right here, it's all just handled for us.

  • Now the sun sets, we go into dark mode.

  • Sunrises, we go into light mode.

  • It's actually pretty fun to play with, but the problem I see here is that a lot of this logic is now taking up space in my app component.

  • And I don't really like that talking about clean code opinions here.

  • But this, I see, is a great example of where we can make our first custom hook.

  • We can actually just take all of that logic and rip it out into its own file.

  • We'll call it used dark mode, and everything in here is exactly the same.

  • Except for we're returning is dark at the very end, and that makes this use dark mode hook extremely versatile in our app.

  • Now we can import that file call, use dark mode, and it's gonna give us true or false.

  • But it's not just true or false.

  • It's true or false that changes over time and all of the life cycle in updating and all of the intelligence of that dark mode is built into that hook, and all we have to do is call it.

  • And that is our first customer for today.

  • That's what everybody clubs.

  • The next thing that I thought every application needs.

  • Everybody has written this 1000 times clicking outside of an element.

  • And I don't know why the browsers don't make it easier to do this, Nate natively.

  • But, uh, you know, I feel like I'm implementing this everyday clicking outside of a menu or ah, motile or whatever, right?

  • And then you want to do something to it.

  • I thought, What about?

  • You know, there's not a better excuse to write a custom component for this, and I thought we might as well just made the assumption that this is going to be a custom hook right out of the gate.

  • So I assume that I could take a ref created by user ref, put it onto whatever element I want to keep track of and then have a handler something like, you know, Consul, logging.

  • Hey, you clicked outside of this thing and I could pass those two things to this use.

  • Click outside hook and it would just work.

  • And I wrote this actually, before I wrote the use quick outside hook to see how reliable it was to design a P eyes around hooks before even writing him.

  • It turns out it wasn't too difficult.

  • We start with the function signature we throw in an effect that's going to set up our event.

  • Listeners on the document for women clicked on the document.

  • Those call our internal listener here that checks to see if the target we clicked is inside of the element that were tracking.

  • And if it isn't it calls or call back.

  • Turns out it just works.

  • Um, and we would probably use this for a little bit and think, Wow, this is great.

  • I'm a genius, but eventually you might notice something very strange.

  • There's something fishy going on here, and it has to do with Theo used effects dependencies.

  • If you're using.

  • Yes, Elin, plug and react hooks, which you should be 99% of the time.

  • It does exactly what you wanted to it.

  • Auto fills effective dependencies for your hooks, so helpful.

  • I love it.

  • You can just hit save.

  • And if you have excellent set up, it will just do the changes for you.

  • And that's what I did here when we built our hook here on the right.

  • You can see it automatically filled in the call back in the l ref down there in our dependencies.

  • But the problem is that the callback is changing every single render from where we're using it on the left side.

  • Here on click outside, we're creating every single time, which means that those event listeners are firing off every single time that we render we're adding and removing those event listeners.

  • That is not cool.

  • Well, it turns out it's pretty easy to just wrap that and use call back from react, and it's going to make it so that that callback function doesn't change unless the dependencies change.

  • There are no dependencies yet, so nothing's going to change.

  • And it will stop, you know, creating those event listeners over and over and over.

  • But this begs the question for me.

  • Why?

  • Why do I have to have that use call back around that function?

  • Um this probably in advance edge case, but I feel like there's nothing inside of my use click outside hook that cares about this callback changing.

  • Um, and I decided that that's part of the A p I.

  • So I wanted to get rid of it.

  • And one of the easiest ways to do that is to Ah, instead of referencing the callback directly, we can use this pattern of tracking the latest version of that call back in a ref itself.

  • And when we do that, the callback ref is now added to the dependency array, which will never change but the value that we hold inside at will.

  • And that way we're only setting up and tearing down that event listener when we actually need to, when the element that we're tracking actually changes.

  • So now there's no call back, we can pass whatever function we want into that use, click outside hook, and that is our second custom hook for today.

  • What's fantastic about this is you can move this around your app.

  • You can import it to as many components as you want, or you can just copy and paste this into another app.

  • There's no external dependencies other than react.

  • I I do this all the time.

  • Greenfield project.

  • I'm like, I really love that hook.

  • I go back to the last project that I was working on.

  • I opened a file.

  • I copy it and I move it over.

  • It's that easy.

  • I don't even really rely on external libraries to do a lot of this stuff because it's just so simple.

  • But something that isn't simple Estate State is as particularly global state.

  • Um, global state is highly opinionated.

  • There's a new way to manage global state.

  • Every day comes out, there's a new library.

  • It's kind of noisy.

  • Uh, and we're gonna be talking a lot about global state here for the last part of this talk.

  • Global state, in my opinion, is something that's always trying to one up you.

  • Uh, it's because you think you have a handle on it, and then your your requirements change and everything changes in your app, and it kind of pulls the rug out from underneath you.

  • This is usually how global state starts, and you're like, Wow, this is so simple.

  • I have a hook.

  • It's gonna return some global state.

  • Theoretically, and then for some reason, it can quickly turn into something like this.

  • Um, not to name names or anything, but this is something I would try and avoid.

  • I don't I don't wanna have to go to these lengths to use global State.

  • I'm gonna take you on a little bit of a journey of finding global state today, and it's going to be so introspective and enlightening that maybe you'll want to actually handle your own global state.

  • After today, let's start by creating a global store, we can use react context to pass values down our reactor tree, not have to pass them through props.

  • We can start with a store provider.

  • That's just, ah wrapper around context that we'll set up some state with a store with a store and a set store function right there that we can pass down through our context value.

  • And then we'll have a use store custom hook that just wraps around that use context.

  • And what that does is in now, inside of our app, we can declare some initial state past that initial state into our store provider and now that state is going to be available to all the components inside of it, including the little two DUIs component down there and inside of us instead of our components.

  • We can consume the store pretty easily by just calling you store, which gives us the current state of the store and a way to update it, which right now is just set state set states kind of boring, and it's ah prone to break.

  • And I don't really feel good about manipulating the store directly from a component.

  • So what if we took it a step further?

  • To use reducer use reducer is really, um, pretty simple.

  • To use my opinion, just create a reducer function here.

  • We could do it in our app.

  • We can pass that, reduce her function into our store provider we created.

  • And instead of use state now you can just use reduce surpassed the reducer, the initial state and instead of a set state function to directly modify the store.

  • Now we have a dispatcher.

  • We can use sonar components.

  • Instead of importing the set state, we get the dispatch, and now we can dispatch actions on DDE have a little bit more confidence about the actions that are taking place inside of our app, especially for, uh, even four components, like an individual to do where we're not necessarily reading from the store, but just dispatching, weaken, Still import Just, uh, we still important store and get a hold of the dispatcher to send off some events.

  • Um, this pattern is really simple.

  • Will probably get you pretty far, but at the end of the day, it might bring up questions about unnecessary renders.

  • You know, I'm re rendering every component in my app every single time that the state changes.

  • Even if I'm only dispatching well, it turns out we can use a concept called multiple context to aid this a little bit multi context.

  • A multi context global store was first introduced to me by my friend.

  • Can't see Dodds, and he's made it popular through a couple of, um, bog posts, which is just fantastic.

  • And he describes creating two separate context for your store and your dispatcher and sending them both down down the line and creating another use dispatch Custom hook there.

  • So now, inside of our components, if we want the store, we use the use store hook, and if we want the dispatcher we use the use dispatch trick.

  • This makes it so that in components that are only using the dispatcher, they're not going to get updated every single time the store updates.

  • And that will get rid of a lot of weird, unnecessary renders around that scenario.

  • Let's take it a step further.

  • What about a single store?

  • Uh, is probably not going to scale for very long.

  • If you have a lot of global state in your application, you don't want every single component updating when the state that you're consuming updates that global state so we can take it a step further with multiple stores.

  • We can take all of that logic that we had to create our global store and just wrap it into a function.

  • And we can create as many of these global stores as we want by passing them in a producer and initial state.

  • So if we wanted to do store, we just pass it.

  • But to do reducer gives us back the provider and a couple of hooks to consume it, and we're off to the races.

  • We come into our app.

  • We provide our traduced to the entire up and you know what I want some global state to ah, manage.

  • All of my men use being open and stuff like that's all.

  • Make a layout store as well, and I'll wrap that around my app and then inside of our component, like our menu that we wanted to click outside and have it, you know, change around.

  • We can hook it up to that use layout store by both subscribing to the store to see if it's open and the dispatcher to make sure that we can talk about clothes when we click outside of it.

  • The next step in our journey is persistence.

  • Right now, our global store isn't really persisting anything.

  • Um, this is extremely important because your users you're going to reload the page and everything's gonna disappear.

  • So let's throw in some local storage.

  • Local storage is pretty easy use, especially if you're using a reduce.

  • Er so right here we can.

  • Instead, she ate our reducer initial value from local storage, and also, every time I reduce her runs, we can save the resulting state into local storage using a key.

  • And now, every single time that your users reload the page, they're going to get the last state that they were left with.

  • I know this is where you guys want to be.

  • Um, and I'm working hard to get you there just to make sure the everybody is awake like that.

  • I got some T shirts.

  • Oh, all right.