[Music]
hi everyone
my name is Sean and I'm here to talk
about hooks what's really great is
inconvenient is that half the room
already knows hooks and users react so I
don't have to introduce it very much my
name is Sean I go by Swick's on Twitter
I work at Nikola Phi is a developer
experience engineer I I moonlight as a
moderator on the reax subreddit there's
120,000 of us talking about react and
getting jobs and getting started and
react if you want to join in hire people
please join us and my other big thing is
that I learned in public so anything
that I learned I try to do talks and
blog posts and share stuff and this is
one of those so I'm gonna start this
talk by talking about Rene Magritte he's
one of these painters you might
recognize the painting in the background
that's one of his more famous ones
that's the man in the bowler hat and he
does several variations of this this
one's probably you've seen this as well
and they're all surrealist like they
look they look really good he has skills
but he just paint something that's not
exactly real and it's meant to make you
slightly disturbed slightly like out of
out of kilter this one's also I really
like this because it's like that it's
just like a floating rock that's
probably the inspiration for Pandora and
and this one I also like it's just kind
of like there's like human intimacy but
they're not really seeing each other you
can't see them he has a thing against
painting faces this one's about I think
in the impermanence of life like things
remain and the the man just goes away
anyway the most famous one is probably
this one I'm not good at French so but
it just says this is not a pipe it's a
picture of a pipe is not a pipe so it's
a it's a it's an interesting useful
model for people to discuss it's meant
to make you slightly off-kilter but well
I think I think it's actually useful
right like you can you can point to this
and everyone knows what you're talking
about as a pipe and this is the the
frame that I want to set this talk with
like this is not a pipe but it is a
useful discussion of a pipe
how does
I have to and I'm updated it for the
Millennials so this is a little bit more
updated in terms of a meme that meme was
like a hundred years old this is bit
more recent and this is the more recent
one I always yeah I'm very good with
means so so how does that have to do
with ReactOS I'm gonna assume that
everyone's seen the talks and see the
see the video as in see the docs
obviously go go check it out if you have
it and mainly hooks were meant to
replace on the problems with classes and
in particular binding that this that's
not the only issue and that's not the
primary issue but that is one of the
issues but but we happen to have
exchanged the problem with that with
with with closures there you start to
run into stale closures all the time and
having to refresh your memory on what
closures are so I was I was running
today as well as well as adopting hooks
and so I looked for a startled look for
definitions obviously you turn the mdn a
closure is a combination of a function
in mexico environment with a function
was declared very clear right and blah
blah blah like i look at all these
comments and honestly the the most clear
one was actually w3schools it's a
closure makes it possible for a function
to have private variables that's the
only time I've ever found w3schools
useful but thank you anyway
so so then I have this exercise of like
why not write hooks from scratch and
practice closures as well because if it
can have private variables I kind of
stateful functions so this is the part
where we start live coding and we have
time okay so what do I mean by stateful
functions let's just have a variable on
the global scope I hope this is big
enough for everyone
variable on a global scope and I'm gonna
constantly I only have a function called
add if I can spell under intense
scrutiny in pledge then pressure food
plus one it's going to return foo and
now every time I call it it's gonna
increment by one right it's a stateful
function in the sense that as every time
I call it there's some internal state
going on that's that's that's being
mutated and and and you can see the
result of that the problem of this is is
thus the the fou variable is on the
global scope so any intermediate script
can just mess of it right like I can
just say like food 999 and that screws
up my my expectations of what's supposed
to happen if I make if I'm writing a
library that's not a good it's not
that's not very secure so I need to
contain I need to protect this variable
somehow and move it off the global scope
and how do I do that I move that inside
the scope of the of the function right
and so now JavaScript just refuses to
run it just doesn't let you modify food
that's great but I give up
the statefulness I gave I just call it
every single time in it and it just has
the same has the same value so how do i
how do I fix this I can't exactly fix
this with this API what I can do is
return a function inside of the function
and do the exact same thing inside there
I'm just a switch this to get add
function higher-order function I guess
and I'm gonna call get add in there and
now it still works again I have a state
I have my stateful function back and I
cannot touch foo inside and internally
right so those are the requirements that
we want we want stateful functions and
we want them to be protected we on that
state to be protected
the last JavaScript refresher so this is
a closure right I add the add function
is this anonymous function in here and
it closes over this full variable that's
inside of the get add function no one
else can access it but and can access it
every time is executed that's closure so
the last thing I'm gonna remind you and
then we will actually start to clone
react is that if I don't want this ugly
get add thing it's kind of ugly I can
just delete this replace get add with a
parenthesis and I'll just paste it in
there and it does exactly the same thing
so this is the module pattern it's also
called be Fe the immediately invoking
function expression a lot of you are
seen if you look at bundler output
alright let's clone react so first thing
when I clone is the used state variable
you state hook it takes an initial value
and in its vowel I'm gonna call it and
what does it return it returns a state
and it's set state I'm going to refer a
lot by the way to the
that the docs like if people knew if
people knew to hugs definitely check out
the docs first before watching this talk
so how do you how do you define state
and set state how do you implement that
we're just gonna have some internal
variable that's just called the internal
value and we're just gonna initialize it
to in it Val we're gonna have state and
it's just a sign that - Val for now this
is wrong but we just get something
showing on the screen and then we'll
modify from there set state takes a new
value and it sets that new value to the
internal Val okay good so now we have
hooks in node let's use it count set
count so this is D structuring or ad
structuring and and all that so again
these are all standard JavaScript
patterns that are pretty handy when
doing this and then now we're gonna
console dot log count we're going to set
counts to two and then we're gonna
console out count again so what I expect
is to log out one and two
unfortunately I log out one and one over
here and that means that I'm not really
it's not really working
unfortunately it actually is that set
count is working
it's modifying internal value but the
problem is when ID structure this counts
is assigned the value of one and it is
one here and it is one here that's what
we're logging out one so we need
someplace to just repoed the internal
state again one easy it's very cheap way
to do it is to turn the state into a
getter function and now I can just call
get I just call the function and now I
have my state full function back again
so one into and and and this is kind of
hooks in note if you need hooks in node
that's that's all the implementation
it's eight lines but we want to do more
than that the in reacts you don't call a
getter function you just used the
variable and it's live every time and
it's just fresh and it's the correct
value don't you don't call it a weird
getter function so we want to model that
but it involves a pretty large refactor
I'm gonna walk you through it you
already know everything that you need to
know so I'm gonna zoom a little bit all
right so the first thing we want to do
is put our hook inside of a reactive
module I'm gonna cut this I'm going to
introduce a react module it's going to
be a function that I immediately invoke
right
I'm gonna paste my hook in there and I'm
gonna return an object that has a u
state property so now the only thing
I've changed is in my usage I can call
react use state and it does exactly the
same thing everyone with me alright okay
cool so so I've done I put I created my
react module and I've sort of wrapped up
my functionality I can do that to my
hook as well
what wraps are on a hook a component
right so I can declare a component and
and that's just a regular function and
put the hook in there normally I'd be
rendering to the Dom but in this case I
don't have a door might just have the
console so I'm just going to return an
object and simulate that we'll get to
the other stuff in a second so render
I'm gonna have consult log counts and
then click this is just for simulating I
don't have a button so we're just gonna
roll with this it's the best you got and
I'm just gonna put in an object yeah
forget the object okay so so the last
thing that we need to do is we need to
teach we have react and we have the
component we need we need to we need to
teach react how to render the component
so that's right the render function it
takes a component and a component is
just a function right so let's just call
it and then the when you call it you get
an object that has a render and it click
right so let's just called the render
all right let's actually just put log
something out on the screen and then
we'll just return it so that we can do
other stuff with the component and I'm
gonna expose that inside of my react
module over here so we're at 16 lines
not too bad
and now I can replace all this logging
stuff and do something like react render
component we should see something show
up on the screen up that's not exactly
what I want but whatever and I can
because there's there's a return value
over here I can take this and I can
start accessing stuff on the object
right like the click function that I
wrote so I can just say click and I can
render it again react I'll click is not
a function oh it's
okay cool it's a little bit like TDD
instant feedback in this rebel thing is
really nice
okay so the only thing that's wrong with
this now is I'm logging the state get er
right that's the that's the thing that
we did just now there was like a hacky
thing let's just get rid of that let's
lift the value up to the the internal
value up to the scope of react and we're
going to get rid of the getter function
we don't need it anymore and we're just
gonna let the getter function close over
the internal value the the you stay
close over the internal value so now it
just returns every single time it
renders so so this is the okay so this
is I'm running into something that I
didn't expect over here so I'm gonna try
to debunk a little bit I think okay so
it comes yeah I think I think I said
comes oh yeah I need two plus one of
course if I'm selling cars to the
original accounts it's not gonna
increment so yeah okay so I practice
this a lot so it's very unusual for me
to screw up like that so you can see we
have our stateful functions back right
but we've gone through a whole buncha
ceremony but now we have a react module
we have a component right it kind of
looks like a component and and we can we
can do things to the component and it
updates in state so that's really good
until you try to have multiple states
multiple hooks so let's just have a text
hook it's gonna look slightly different
so that you can differentiate between
the number and the text I'm gonna call
it apple just because that's the first
thing I think about I'm gonna log it out
as well so we're gonna log it out in our
render and I'm gonna have a new method
I'm just going to call it type I'm just
gonna take a word and it's gonna set
text to that word okay let's get rid of
this and we'll use that type function
here and you'll see what's wrong with it
in a second so I'm gonna set that to
pear okay so so what's happening here
our component is here it's got two hooks
the first click happens and and both
counts and texts are both set to two and
then we
at that type and both counts in Texas
both set to pair so what's wrong with
this this image we are trying to use to
a hoax but they're they're they're just
oh they're just using the same store in
the memory right because we only have
one variable and it's constantly
overwriting that single variable so the
the mental image of hooks that you have
now should grow a little bit and you
should think of hooks as a rays of
effects so let's just use an array and
we'll stand to know which hook we're
currently operating on we also need an
index so I'm gonna have an index of zero
so so now now we're now it's pretty
clear we're gonna replace all the
internal values with just hooks and in
the current index so now nothing has
changed because we're still not oh it's
not incrementing the index so I'm gonna
have a rule there at the end of the at
the end of a hook after we're done we
should just always increment the index
so that the next hook can take and can
take place so now we have an
independently updating counts and text
is not changing that's good but over
here we still have this weird bug and
that's because I just keep incrementing
index plus one plus one plus one plus
one I need to reset it back to zero so
that every single time a rerender it's
gonna start and go through all these
hooks from scratch because it's
referring to their internal hook storage
so yeah let's just set it to zero and
now I'm gonna break everything and this
is because of a very subtle bug again
set state is called asynchronously set
state is called after a render right and
and by that time hope the the indexes
actually set back to zero so this this
index being a live value that's a
problem for us the way to fix that
problem is to freeze it so let's have an
internal index and we'll just freeze it
and we'll that set state closed over
second NewsAsia closure close over that
internal frozen index value okay so now
we have a component we are rendering it
we have a count of one we're clicking
the account updates to to the text
doesn't change then we type pair and
then count doesn't change and tax
changes so we have independently moving
states right and that's something that's
a new paradigm in the hooks model as
well that you every component used to
have one object for state and everything
you're just forced to put every all you
stay on today
checked now you have independently
moving states and you can be a bit more
precise with that alright so and you can
already start to see some of the issues
we've hooked some of the rules of hooks
so these are when the people introduce
hooks I think one of the biggest
problems with folks that people had was
that you you can you have to call them
unconditionally you couldn't put them
inside an if or a loop or some sort of
dynamic value so I just want you to
imagine what happens to this if I do
like math dot random more than five
point five right so this gets this gets
called half of the time what is the hook
index value of this this is this should
be one the okay next value but sometimes
it's zero because this doesn't execute
and so the the the state values get get
off right so you're just not allowed to
do that and that's what we have linters
that's why you understand the rules
looks just a fundamental basis okay so
we're not done I'm not happy we only
have the state hook we also have the
effect hook the best way to model this
is to just use it and then we'll
backfill what that what that is so a use
effects hook takes a call back or just
say console.log yes calm and then it
also takes an optional dependency array
I'm just gonna use an empty array for
now all right so so we have that API
let's just let's go and implement it
right so this is our module again so
function use effects callback and
dependency array okay so this is the
hardest part of the talk bear with me
but I have I know what I'm doing so
we're good so so we want to have this
variable we'll just have like like
whether it has changed or not and just
set it to true so by default we're just
going to keep rerender ring and if if
the dependencies have changed we're
gonna call the callback right that makes
sense if the dependencies have changed
we're gonna call the callback so the
hard part is to detect change over here
in order to detect change we need to
basically diff the old dependencies and
a new dependencies that means we need to
store and keep around the dependencies
somewhere where's the good place for
that turns out it's the hooks array so
we're going to store it inside of the
hooks array and we'll draw it out at the
start of our effect
the old dependencies so hooks index okay
sometimes this is undefined though so so
that's why we need to guard it with an
if oh and by the way always increment
the index at the end of talk okay so
sometimes it's undefined so what we're
gonna do is replace this and just go if
the old dependencies do exist that means
we have an old array and a new array
this is the hardest part in the entire
code so bear with me so we're gonna
modify has changed to look at dependency
array we want to have we want to look at
some of them we want to do a ray dot
some and that's just a lesser known
array prototype method we want to look
at the dependency and that index and we
want to compare that dependency to that
index we're gonna use object dot is so a
lot of people like I don't know it
internal is react to use this object is
internally because not a number triple
equals not a number is false object dot
is not a number and not a number it's
true so that's just a slightly better
option so people went with that so we're
just going to say object that is
dependency and the old dependencies the
corresponding index of that old
dependency I think that's it oh and then
we need to expose it in our reactor
module ba-boom so what do you have now
we have a component with a use effect of
an empty array it start it only runs
once at the start and never again in in
any of the updates if I put in counts
here then it depends on that counts and
it updates when the count changes from
one to two it runs if I change it to
text from when the text updates from
Apple to pair it runs and when I delete
it it also runs every single time so
that's the spec of use effect and it
wasn't that hard right to implement all
this so this is normally where this is
as far as I plan to go I was like okay
you've kind of proved out the hooks
model but I'm very been ambitious person
and I was like this kind of looks like
react but is not really react everyone
kind of knows that so what can I do to
put this on the Dom which is a really
stupid question to ask
we're live coding talk but we're gonna
do it we're gonna this looks like node
but actually we have not been coding in
node at all it's just been the console
and I have it I have a browser
implementation here thanks to code
sandbox so let's do it
actually that was probably a bad idea I
have some I have some pre-prepared CSS
I'm gonna import that it's not showing
the autofill an immediate background
very nice CSS effects for demos and then
I also have some utilities that I
imported so I have a create element
object that I have from my utils folder
and create what create element does is
is what JSX compiles to by babel right
hopefully everyone knows that i'm gonna
expose it inside of my inside of my
react module and now I can use JSX
inside of my component so I'm gonna say
Dave hello well let's get something to
show up on the screen unfortunately
we're not done oh sorry let me just
comment it out unfortunately we're not
done we also need a render function that
actually renders to a Dom element so
let's just import render okay the render
API that I have written is slightly
different because it memorizes the hooks
so I'm just gonna delete the render
function that we wrote and I'm gonna
expose the render function it's a high
order function it just takes the hooks
and it in and it has an E and it outputs
a render function that we can actually
use like you wouldn't use a normal
render function so let's just go like
that very nice so we have JSX this is
JSX and it only works because we act our
create element in the Babel JSX plugin
okay
let's keep going so so what do we do
let's actually prove out that everything
works and and this is a full reax clone
it's not but trust me so let's have a
button i took the opportunity to alright
you'll see what happens I'm gonna write
a standard event handler it's gonna set
counts to count plus 1 I it was the
first time I ever forgot
plus one and obviously it's on stage
very stressful and it just says click me
for example and then it's gonna have the
current count yeah everyone should be
very familiar with this I don't have hot
reloading figure it out so you're gonna
see me manually refresh a few times so
yeah
button showed up I have nicely some nice
CSS because I cheated but if I click it
it doesn't work why mmm
because when remember when we were doing
this we were manually rerender every
time right there reactions this concept
of a work loop
it always loops around to check if
there's work to be done so we need to
simulate this work loop by manually
doing it and also screw it I can write a
work loop that's not too hard right it's
only you know we've got like 10 minutes
so let's write a work loop and the work
loop is simply I'm gonna set the index
to zero because every time you render
you have to set the index to zero we're
gonna call the render function again
pass in their hooks argument and then
we're gonna call the set timeout with
the work loop
I'm gonna set a loop of 300 milliseconds
in reality it's it's of course I will
call back so it's much faster but this
is what you get this is what works for
this demo so we have clicking we just
live code at this the last point I want
to make I think in this entire thing is
I have custom hooks notice that we did
not write any any custom hooks code
right nothing here was specific to
custom hooks but if I paste this
pre-prepared custom hook that's I have a
used dogs hook it it has it has a state
it has an a which has an array it
fetches an API based on the counts that
like feed in count is 1 2 3 4 5 and it
gives back a number of pictures a number
of URLs of dog images and it just
returns that image so I can use this
custom hook again I didn't I didn't I
didn't do any I didn't do any custom
hook specific code right I can use dogs
it once accounts so I pass in the count
from there and I can render that into
map item bog-standard stuff completely
and not accessible by the way but I'm
the only one accessing this code anyway
so it works fine you should have an alt
tag so so let me yeah all right
again I haven't figured out hot
reloading so but this is a fully working
app so thank you thank you so then I'm
like okay so the punchline what is the
punch line this is the punch line I'm
just gonna paste it in and I'm going to
remind you of what we're talking about
this is not react this is not react I
have a fully dynamic app yeah I have the
full API I have JSX I have custom hooks
I have the render I've cloned everything
that you usually use this is not react
why I cloned this in 40 lines of code if
you magnify it if it's in a tweet if
you're if you're wondering about the the
you tools folder by the way the you
tools folder is only a hundred and
twenty lines and it's mostly helper
functions like create text element and
all that that JSX needs so this is
normal what is react so that's a that's
my that's where I'm gonna leave you that
I have homework for you I want you to go
home and write react from scratch I want
you to practice I want to eat we need to
practice closures I want you to get good
at like understanding the mental model
and understand what you use react for
you don't use react for this API API is
really good right we can copy it view or
you will copy it like spell copy n but
what do you use react for what is what
is the hundreds of thousands of lines of
code what is that for I have my answer
I'm gonna tweet all this out later but I
want you to have that curiosity don't
just stop at the surface and that's my
talk you can see the full source at
Strix that i go slash talks thank you
you