 Thank you. Okay, okay, okay. Last talk of the day, I know everyone's tired. So I'm gonna try to make this as exciting and interesting as possible for you. Very high energy, high risk, high reward, okay? And first of all, I wanna give a shout out to Nick. I don't know if you're in the room. Nick was originally supposed to speak tonight, but because I wasn't, I'm not gonna be in Singapore beyond Sunday, so he kindly gave up this spot. So I'm doing a favor back to him. Please check out his TDD talk next meetup. So I'm gonna do this talk. This is a live coding talk, which is difficult given this. I also was tempted to change the topic to TypeScript Be Happier. I think. I'm a TypeScript fan, but, and I think there's some others as well. But we're gonna stick to Hook. And this is the Right Hooks From Scratch talk. I've given this at JSConf Asia already over the weekend. And Wei here actually has seen it multiple times. So I thought it'd be more interesting because I don't have a standing mic or anything. If she takes over the live coding and I'll narrate it to you, we're doing pair programming. She has, so hands up for her for Wei. Okay, so very exciting. This is completely unrehearsed, by the way. But she's seen this talk multiple, oh, what is this? Nope, you didn't see that. Okay, it's completely unrehearsed, but I'm basically just gonna, we're gonna do pair programming. Okay, so the first thing we're gonna do is we're gonna clone Hooks in JavaScript, raw JavaScript. So the first thing we're gonna do is clone UStates. So we'll write the first function, the UState function. What, and then use the function keyword. What does the function, what does UState take as a argument? We'll just call it initial value, like init val or something, right? Put a parenthesis in curly brackets. All right, yeah, all right, curly braces. What does UState return? Anyone? Array of state and, so state. Excellent, let's define them, right? So we wanna have, in Hooks, we wanna have this idea of stateful functions. So let's define an internal val, like an underscore val function. And you should not use const, because const doesn't let you reassign to them. That's ES6 tuition for you. Let's initialize it to init val. And also let's set state to init val. So in the next line, let's set state equals init val. So this is probably wrong, because it will never change from init val, but we'll fix that in a future iteration. Set state is a function, so let's declare const set state equals new val. Yeah, yep, let, yep, okay. So set state, we can use the arrow functions in text. New val, it takes a new val, for example, right? And then, that's, yep, and then we'll assign that to our internal value. So underscore val, right? That's the internal value, and then we'll assign the new val to that. Okay, I think there's some typos in there. New val and new val. Okay, is this big enough for everyone, by the way? I hope that is, yeah, there's an extra E there. Okay, so cool. Now we're actually, that's the minimal use state clone. So actually, let's go use it at the bottom. So in, no, let's just exit the function and go all the way to the bottom. So we'll destructure something, right? Let's say a counter. Let's have a count and set count variable. She's doing an amazing job, by the way. Let's, yeah, initialize that to one. Let's console log the count. This is amazing, I don't even have to code anymore. Right, come on, we all have this. I will set the counter to, and then we'll console log count again. You can copy it by doing the shortcut for copying the line. No, I don't. Okay, I'll teach you later. Okay, so over here we have like a repos type environment. Let's blow it up a little bit. Hopefully that, hopefully that's, so right now we're only seeing one, right? One and one, we're logging the count over here. We should be setting the internal value to two, but we're not doing, we're not quite doing that, because, and basically that's just because when we destructure from here, count is set to one. It's one over here and it's also one here. There's no opportunity for it to update. So really what we need is to turn the count into a setter function. Wei already knows how to do that, because that was the first comment she had to me when she was seeing this slide. It's underscore val, yep, okay. So now it's a setter function, we're logging out state. So let's go to the bottom and the console log and turn those into function calls. And now we have stateful functions, right? One updates to two. So we have a minimal clone of hooks in node, but that's unfortunately not the actual API of React, in React you don't have getter functions, you just have the variable, you just use it and it's just live, it's the right value every single time. So in order to do, in order to get closer to the React API, we have to break the model a little bit. It's a big refactor, but I'm gonna guide Wei through it and she's very bravely helping us. So the first thing is we're gonna name space, you state inside a React object, right? Do you know how to do that? So we'll say const react equals, and immediately invoked function, right? So we'll put a function in there. So this is the module pattern. If you look at bundler output, you'll see this. So we're gonna cut that and paste that in there, in that function. And then we're gonna return, at the end of that function that we're immediately invoking, we're gonna return an object that has a use state in there, fantastic. Okay, so now at the bottom, in the usage code, we can just say react dot use state, and everything still works as normal. We've always done is we've name-spaced everything in the module pattern. So that's the React mini clone that we have over there. So what we've done to the use state clone over there, we can also do to the hook. Let's wrap that in a component. So we'll call function component, so we'll just name it component for some reason. Doesn't take anything. Brenda says put the hook in there. Do you know how to move it up? Vimperson. So I think it's a alt and up. Alt and up. Hold alt, alt, yeah. Ah, yeah, there you go. Okay, let me minimize it a little bit. Okay, so cool. We normally would be rendering to the DOM, but we don't have the DOM here, we just have a REPL. So we're just gonna return an object. And this object will have a render method. Let's just type render, and then we'll make it arrow function that just console logs the current value of counts. Yeah, we can do that, okay? We're also gonna expose another method, a click method. It's another function as well, and then it's just gonna set count to count plus one. So that's simulating a button, right? All right, so that's all fine. So we have something like a component down in here. So the last thing that we need to do is we need to teach our clone of React how to render this function. This component function. So we need to write a render function inside of React. This is all unrehearsed, she's doing an amazing job. So it takes a render function, takes a component, right? A component is after all just a function, so we'll call that function. Let's just assign it to something called like C or comp, or I don't know what, app. Whatever you call it. Assign it to like C, I call it C in my code. That C equals component, a comp, and then just call it, right? So the component is just a function. We're calling it, and now we have the return object of what we just wrote. So now we have the object, let's call C dot render, right? That's just for rendering and doing the console log stuff. And then we'll just return C so we can do other stuff with it. Okay, cool. Now we're ready to actually just rewrite the usage code at the bottom. Did we delete it already? Yeah, we did. Let's just go all the way to the bottom, right? And now we'll actually use what we just wrote. We'll write react dot render component. Okay, so we'll see something showing up on the screen. React dot render is not a function, so we need to expose render on that object. Cool. So we start to see the getter on the screen. Let's carry on. So let's assign the result of react dot render into a variable. I use var app, so I want to use var because I reassigned it. So var app equals react dot render. All right, and now we can say app dot click, right? And now we're calling, we're just calling this set count function. And then we can var app equals react dot render again. So this one is, I think it's alt shift down to copy a line of code. So go up to that line, alt shift down. Alt shift down. Yay, that's a handy keyboard shortcut if you didn't know it. So let's have a render before the click and then we'll click and then we'll render after the click, right? Oh, come on. No, no, no, move it up, move it up again. I'm sorry, I shouldn't be yelling at you. Move it up. Yeah, there you go. So you don't have to call render. Don't have to call render because react dot render already calls render. Okay, so that's roughly the thing except we're only, we're still showing the state getter function here. So let's refactor that, right? We don't want to show state getter function. So let's go all the way up. We're going to promote the scope of val, underscore val over there, promote it up to the react scope, the react module scope. Let's cut and paste it up there. Yep, okay. So initial val, let's just let it be undefined. Let's delete initial val there. And then instead of, and for state, now instead of the getter function, right? We're just going to assign it underscore val or initial val, right? So if there's something in there, use that. If not, use initial val. And so now you can see something interesting. We've got back to our stateful function and over, if you scroll down all the way to the bottom, we're just rendering, clicking and re-rendering. And if you just spam it out a few times, you use the alt shift down thing and with the, with the clicking, you can see the, you can see the statefulness of the, of the function. Okay. I should have shown you the keyboard shortcuts first. Okay. But you can see that numbers are updating here as you click and re-render and it kind of sort of looks like react, right? Which is pretty interesting. Until you try to use a second hook. So let's try, let's try to use a second hook. Let's just call it text and set text. Do you know where to put it? The second hook? Yeah. So we got the text and set text. We'll put something like react SG as like the initial text or shoppy or react SG or whatever. Okay, react SG. I tried to customize it, you know, to like make it interesting and live and all that. Let's put the text in the console log for the render. The text variable that you did. You know the console, yeah. The render method. Yeah. Okay. All right. Cool. And then for, and then we'll expose a new method called type and alongside of click. It takes a word, it takes a word variable, okay. And then it sets text to that word. All right. So now let's, let's change one of our app.clicks into a type, app.type. And then we'll put in a new word, like view. I don't know. Okay. So, so let's, let's delete the rest, delete the rest of the renders. And then we can start analyzing this code. All right. So I'm gonna have you, I'm gonna, okay, I'm gonna have you consolidate these things. So console, the console logs here, can we combine them into one object? You know what I mean? Like, yeah. Make it into objects and text, exactly. It's easier to see side by side. So, so you can see individual renders. Okay. So, so what, what's happening here? Let's put a last render at the bottom as well. Just clone that, I'll shift down, put one more app.render at the bottom. Come on. Yeah. No pressure. Okay. She's got it. So what's happening here is we're trying to set, we're trying to click, right? Click should move the counter from one to two, but it also starts to, starts affecting the text state over here. And we try, we try to set this text state. It, it's supposed to only update the text state, but it also affects the counter. So we don't have independently moving states. That's a problem for us. Why, why do we have that? The answer is all the way up there, scrolling up all the way. We only have one internal value and we keep overriding that every single time. So we need to make room for that. Like we need to scale that to multiple hooks. So let's turn that into a hooks array, right? BAM! Underscore value. Oh no, yeah. Well, we'll just call it hooks. Let hooks equals empty array. And instead of just an individual value, we need, now need an index. So we'll just say like let index equals zero as well. So that's the current index of the hook they were currently operating on. So we'll just replace all the current references of underscore val to hooks index into that. And then the second, yeah, yeah, you're doing great. And then that's the only other occurrence of that. So what we're doing is just we're replacing any references to internal value to parameterize it by hooks index. So now we fixed something. Look, look, look. The state, actually we haven't fixed anything. And the reason is because we need to bump the index every time we're done with a hook so that the next hook can use the second slot and the third slot and the fourth slot. So let's bump it. Oh yeah, okay, she's already ahead of me. So count is now updating to two and text is not changing. Good. But then over here, something weird is happening. We're updating text to count and then this is not changing as well. So something's going wrong. We need to reset the index to zero every single time we render because we need to go zero, one, two, four, three, four and then back to zero, one, two, three, four, right? So we need to reset every time at the start of a render. At the end also works, but let's just do it at the start. And now we've completely broken everything because of very subtle nuance because of closure and basically like still closure. So over here in the set state, this is called asynchronously and whatever this index value is, it's going to be live and the latest value. And that's going to be true for any set state that's being called in here. So we need to freeze the value of index. We're going to freeze the value in a scope of use state. Do you know where to freeze it? Just freeze it in here. Just insert a line in between. Insert a line, yeah. Nope, one more here, yeah. Yeah, so we'll freeze the value to like just underscore index. Yeah, equals IDX. And that's at the point that is being called, at the point that use state is being called. So we just have, we make sure that we have the matching use state. So let's assign it to let, use a let or const, doesn't matter. And then let's change the one that we're using down inside set state to underscore index. Okay, cool. So now we have, we click the count is updating from one to two. Text is not changing. We type a new text, count is not changing and text is updating. That's great. Yeah, so I mean that's a very basic set state hoax clone and we've done a fantastic job. I won't have a round of applause for her. Yeah, I'm going to take over. But we're not done. I just wanted to like not have her hold the mic for me for the whole thing. But I just want to keep going and show the rest of the models. The second hook that they're well very interested in is the use effect hook. And the API kind of looks like this. So it's react.use effect. It takes a callback, right? And then we'll say callback something like, thank you for the pizza. And then it takes an optional dependency array, right? That's the use effect hook. I'm really leaning on the fact that this is a React meetup. So I assume that most of you have heard of hooks in some shape or form. So now it's throwing an error. So we're going to go and implement it. This is actually the hardest part of the talk and I didn't want to force way to go through it. So we're just going to implement a use effect function, right? So it takes a callback and a dependency array. And basically what we want to do is call the callback. Every single time we render, by default we just call the callback of use effect which executes stuff asynchronously in the hoax world. We also want to detect change in the dependency array. So we'll just assume that the dependency array is always changing. So I'm just going to say by default that has changed equals true, for example. And then I'm going to guard that by putting an if in front of the callback. So if it has changed, if the dependency arrays have changed, then you call the callback. So then the only thing tricky is to detect change between two arrays of items, always the same size. That means we need to compare the old dependency array and the new dependency array and see the differences. So that means we need a place to store them in between renders. Where's a good place to store them? It's the hoax array, right? So that's a very nice place to store them as well. And we're also going to... So at the start of a render as well, then we need to pull it off and we'll just call it const, like old dependencies. And we'll pull it off of there. So that could be undefined. So we'll have to say if old dependencies, then we'll do some magic. And then we'll try to see if the change has actually been executed between... Again, we're comparing arrays, right? So we have to kind of zip between them. Okay, so this is the hardest part of the talk. Basically, I have to modify this according to line by line, just compare the indexes of arrays. So I'm going to use array.sum. Some of you may not be that familiar with this. It's kind of lesser use. But it basically goes through and looks at individual list items. And if any of them is true, then the whole thing is true. So here I'm going to compare them with... Oh, and here I'm going to use object.is instead of triple equals. So for those of you who don't know, nan, triple equals nan, that is false, correct? Whoever said that? And object.is, nan, and nan, that is true. So this is slightly better in case any of your dependencies ever become nan, which never happens, but whatever. That's just what React uses internally because of this reason, and because JavaScript is weird. So we'll say object.is, old depths, correct? The current depths and the old depths indexed by that index as well. And then we'll have a knot in there because that's the logic of that. So let's take that use effect and then we'll expose it on the react object over here and now we can see something. So when I have an empty dependency array in my use effect, the effect only runs at the beginning. When I have a count in my use effect, it runs when the count changes from one to two and nowhere else. When I start to subscribe to the text changes, the use effect only runs when the text changes and not when the count changes. And I remove it and I have undefined as my dependency array just runs every single time. So that's a good implementation and intuition of what the use effect hook does. You can do a lot of extra stuff with this idea, but you can also start to see why we have the rules of hooks. The rules of hooks state that you cannot put them inside a condition like math.random and then like less than 0.5, whatever and then put this hook inside there. What is the index of the second hook after this? The index is sometimes zero, sometimes one. It's unpredictable and you start to get out of killer. So that's all you have adventures to prevent you from doing that kind of stuff. And if you think about the rest of the rules of hooks, they're actually basically derived from that. You can also do, this is special, I didn't do this at GSConf, but you can also do other forms of hooks as well. I'm gonna do react.useref. So let's just have a ref equals react.useref one. You can store whatever you want in refs now, previously you only store DOM elements, but you can store whatever you want in refs now. And the way that you use refs, for example, is in, for example, like this, ref.current, right? And then you set ref.current in something where you don't want it to store, you don't want to store it on state. So the way that you implement react.useref is a one-liner in react. It's literally useref value, return, use state, val, and it's an object, current, val, and then index to zero, because you never set state for ref. So that's react.useref if I bother to also expose it down in here. And you can go through the same exercise for use reducer, and it takes a little more effort for use context as well. Okay, so all this is well and good. I think that we're all here to put stuff on screen, and I don't think this is very convincing as a react clone. So let's just take it the final mile, and we'll just show stuff in the browser. So even though this looks like a rebel, this actually has been in the browser console all this while, and we're just gonna start showing the browser, and to prove to you that this is the browser, I'm gonna import some pre-prepared CSS. So I'm gonna styles.css, styles, styles. Okay, and there's a nice animated background to show you that we're actually rendering the DOM here. We're also gonna import some other fun stuff that I prepared as well, basically two functions, create element and render from my utils folder. So create element is the basic create element of any JSX and react functionality. So we're just gonna put that down inside my react module, just re-export it inside of react. And now I can say something silly like, I don't know, like react.create element h1 null hello world. Unfortunately that's not showing up on screen yet because I need to teach my renderer method how to render this kind of new component. So let's use my new render method. Let's delete my old render method, which is just a stupid simple four line thing. Thanks for that though. And it's a higher order component that memoizes on hooks. You can definitely see the code after this talk. And we'll finally get rid of this series of imperative steps here. And we'll just declaratively say what we always say, which is root element, get element by ID and then react.render or something, right? So let's try and see. Hey, that's pretty cool, right? So we have react.create element and we're creating this little thing. So for everyone who knows JSX, what does this become? It's just an h1 tag, right? Hello world. I have the Babel plugin installed here. And I don't have hot reloading figured out, so I'm just gonna manually reload every single time. Okay, so let's do the final step, which is turn this into a fully working app and then we'll talk about what we're supposed to take away from all of this. I'm gonna use the main because that's what my CSS expects me to use. And then I'm going to use, I don't have syntax highlighting in my JSX, which is very funny. I'm gonna use the button and it's gonna have a click me function. So set count, count plus one and then it's gonna say click me count and it's gonna close the button. So that should show a nice little button here. And it should update when I click, but it doesn't update. And why is that? Because we used to manually re-render every single time. We haven't simulated that re-render every time. In React, this is called, this is the concept of a work loop. It just cycles every idle callback and it checks for work to be done. We're gonna simulate this with our own work loop. I can definitely write that in a few lines. It's just a recursive function. It sets the index to zero because that's what you do every time you re-render. It calls the render function here. Again, you don't know this but this is the new API for the render function that I imported up there. And lastly, it's gonna set timeout for the next loop. So work loop, I tested it out for hot reloading and stuff and it's 300 milliseconds every work loop. And then I'm gonna initialize that. So that's the work loop and now when I click, it actually updates. Which is pretty cool, right? We just live-coded this entire thing without actually using React but it kinda looks like React. And now just the final clicker, which is that with this mental model, I haven't done anything specific to custom hooks but it already builds that in terms of the design. I can just paste in this preprepared custom hook or I can import it in from whatever. This is a fetch dogs custom hook. It just pings an API, it has a state which is an array. It pings an API and it gets an array of dog images based on the counts variable that we feed in, like one dog, two dog, three dogs. And then it returns those, that array of URLs. So I can use that inside of my component in here. So const list equals use dogs and then we'll just pass in the counts as well. And now we can actually use list. This is going nuts, don't worry about it. List, hot map, item, image, source. You see, this is, we're all about getting things to show up on screen. This is why I have to do this. I have to show you dogs. I have to show you that when I click it updates and it looks like a fully functioning app. This is pretty cool, right? I was pretty happy. Thank you. So this is like a bit of a party trick, right? Like, okay, I did, I cheated, I prepped a lot, right? But look at the API. Look at, look at, this is a function component. It uses state. It uses custom hooks. It uses JSX. It really doesn't take that much work, right? I even like, you know, use custom hooks and do like data fetching like you're supposed to in Hooksland. That's pretty, I mean, this is exactly the API. So why again do we download 30 kilobytes of reacts every single time? That's interesting. So that's the homework that I want to leave everyone behind with is that, you know, this is not React. This is the surface level stuff that we use all the time. This is what we talk about. This is why we say we choose one thing over the other thing. No, no, like there's, please look at the underlying levels of React. Look at why you really, you know, what parts of React you really don't spend that much time on. I have some answers and I can talk to you after the break with some answers. But yeah, thank you so much and thank you, Wei. Thank you so much. You have to shake your hand. Hey, can we take a photo together? Oh, oh, that's, oh, okay, you can have a stick. Yay! Okay, that's it, that's that. Yeah, it's all about the dogs. Okay, thank you. Oh yeah, do we have time? Do we have time? Does anyone have questions? Sorry. Yeah. No, no, those, those global store is a separate thing. That's, you can have multiple contexts to replace that part of Redux. But if you only use Redux for that, then you're not really using Redux as it was intended, which is to chain a bunch of middleware to help you develop and audit your, your app. So, no, React records do not replace Redux. In fact, Redux just introduced some new React hooks in Redux, React Redux 7.1. I've actually used them and they're very good. They're much improved API over normal Redux. Okay, yeah, and like the whole point of this is that you can definitely go home and clone this. This is on my site, this is on my Twitter. It's not that many lines of code. You can take the code sandbox, but try it and then practice closures, practice vanilla JS and what your core understanding of React is. All right, thank you. Thank you. Hello folks, we have other Redux in the future. We have one in July in my office. So if you could just share something with the community.