Deep Dive: How Do React Hooks Really Work? (2023)

Author's Note: This article wasturned into a conversation, with more context. Also, this article does not mentionder React-Schedulerohow state is actually stored in react.

Hookthey are a fundamentally simpler way to encapsulate stateful behavior and side effects in user interfaces. they arefirst introduced in Reactand were used by other frameworks such as for examplever,Skinny, and even adapted togeneral functional js. However, its functional design requires a good understanding of JavaScript closures.

In this article, we reintroduce closures by creating a small clone of React Hooks. This serves two purposes: to demonstrate the effective use of closures, and to show how you can clone hooks in just 29 lines of readable JS. Finally, we come to the natural formation of custom hooks.

⚠️ Note: You don't need to do any of this to understand Hooks. It might help with the basics of JS if you do this exercise. Don't worry, it's not that hard!

What are closures?

One ofmany outletsThe use of hooks is to completely avoid the complexity of higher order classes and components. However, some think that with Hooks we trade one problem for another. Instead ofConcerns about the linked context, now we mustconcerns about closures. SeMark Dalgleish memorably summed up:

Deep Dive: How Do React Hooks Really Work? (1)

(Video) How Do React Hooks Actually Work? React.js Deep Dive #3

Closures are a fundamental concept in JS. Despite this, they are known to be confusing to many, especially newer developers. kyle simpsonyou don't know jsGlory defines closures as such:

Closure is when a function can remember and access its lexical scope even when that function is executed outside of its lexical scope.

Obviously, they are closely related to the concept of lexical scope, whichMDN definedlike "how does a parser resolve variable names when functions are nested". Let's see a practical example to better illustrate it:

// Example 0
function useState(original values) {
Guerra_val=original values// _val is a local variable created by useState
function Disease() {
// state is an inner function, a closure
go back_val// state() uses the _val declared by the parent function
}
function setstate(NeuVal) {
// The same thing
_val=NeuVal// Define _val without exposing _val
}
go back [Disease,setstate] // Make functions available for external use
}
Guerra [Foo,setfoo] = useState(0) // Use array destructuring
console.Protocol(Foo()) // log 0 - the initial value we gave it
setfoo(1) // define _val within the scope of useState
console.Protocol(Foo()) // record 1 - new initial value despite the same call

Here we create a primitive clone of ReactuseStateHook. In our function there are 2 built-in functions,Diseasemisetstate.Diseasereturns a local variable_valdefined above andsetstatedefines the local variable for the passed parameter (i.e.,NeuVal).

Our implementation ofDiseaseHere is a getter function,which is not ideal, but we'll fix that in a moment. This is important withFoomisetfoo, we can access and manipulate the internal variable (aka "Close")_val. You retain access touseStatescope of , and this reference is called a closure. In the context of React and other frameworks, this looks like a state and is exactly what it is.

If you want to delve deeper into the conclusion, I recommend you readMDN,YDKJS, miDiaryJSon the subject, but once you understand the code sample above, you'll have what you need.

Use in function blocks

Let's apply our newly minteduseStateCloning in a familiar environment. we make atrocarComponents!

(Video) How do React hooks really work Under The Hood ?

// Example 1
function trocar() {
until [say,setAccount] = useState(0) // same usage state as above
go back {
clique: () => setAccount(say() + 1),
do: () =>console.Protocol('do:', { say: say() })
}
}
until C = trocar()
C.do() // render: { count: 0 }
C.clique()
C.do() // render: { count: 1 }

Instead of rendering to the DOM, we choose right hereconsole.logof our state We also provide a programmatic API for our counter so that we can run it in a script instead of attaching an event handler. This theme allows us to simulate the rendering of our components and respond to user actions.

While this works, calling a getter to access the state isn't exactly the API for reality.React.useStateHook. Let's fix this.

deprecated closure

If we want to match the actual React API, our state needs to be a variable instead of a function. If you'd just let it go_valInstead of putting it in a function, we'd run into an error:

// example 0, revised - that's BUGGY!
function useState(original values) {
Guerra_val=original values
// no function status()
function setstate(NeuVal) {
_val=NeuVal
}
go back [_val,setstate] // expose _val directly
}
Guerra [Foo,setfoo] = useState(0)
console.Protocol(Foo) // registers 0 without requiring a function call
setfoo(1) // define _val within the scope of useState
console.Protocol(Foo) // window 0 - oops!!

This is one form of the stale closure problem. when we break it downFoofrom the exit ofuseState, refers to_valFrom the beginninguseStatecall... and never change again! We don't want that; In general, we need the state of our component to reflect this.actualstate while it's just a variable instead of a function call. The two goals seem diametrically opposed.

completion in modules

We can solve ouruseStateSolve puzzles by moving our shutter to another shutter! (Dude, I heard you like closures...)

// Example 2
untilMy reaction= (function() {
to allow_val// keep our state in the module scope
go back {
do(Components) {
untilcourtesy= Components()
courtesy.do()
go backcourtesy
},
useState(original values) {
_val=_val||original values// reassign each run
function setstate(NeuVal) {
_val=NeuVal
}
go back [_val,setstate]
}
}
})()

This is where we decided to use it.the module patternto create our little React clone. Like React, it tracks component state (in our example, it just tracks a component with state in_val). This construction allowsMy reactionto "render" your functional component, allowing you to assign the internal_valValue always with the proper closure:

// Continuation of example 2
function trocar() {
until [say,setAccount] =My reaction.useState(0)
go back {
clique: () => setAccount(say+ 1),
do: () =>console.Protocol('do:', {say})
}
}
to allowApplication
Application=My reaction.do(trocar) // render: { count: 0 }
Application.clique()
Application=My reaction.do(trocar) // render: { count: 1 }

Now this looks a lot more like React with Hooks!

(Video) How Does React Actually Work? React.js Deep Dive #1

CanRead more about module pattern and closures in YDKJS.

replicateuse effect

So far we have covereduseState, which is the first basic reaction hook. The second most important catch isuse effect. not assetstate,use effectit runs asynchronously, which means more opportunities for completion issues.

We can extend the small React template we've created so far with the following:

// Example 3
untilMy reaction= (function() {
to allow_val,_deps// keep our state and dependencies in scope
go back {
do(Components) {
untilcourtesy= Components()
courtesy.do()
go backcourtesy
},
use effect(call back,depArray) {
untildoes not have deps= !depArray
untilhas changedDeps=_deps? !depArray.one((Y,UE) =>Y===_deps[UE]) : TRUE
Se (does not have deps||has changedDeps) {
call back()
_deps=depArray
}
},
useState(original values) {
_val=_val||original values
function setstate(NeuVal) {
_val=NeuVal
}
go back [_val,setstate]
}
}
})()

// To use
function trocar() {
until [say,setAccount] =My reaction.useState(0)
My reaction.use effect(() => {
console.Protocol('It's done',say)
}, [say])
go back {
clique: () => setAccount(say+ 1),
No: () => setAccount(say),
do: () =>console.Protocol('do', {say})
}
}
to allowApplication
Application=My reaction.do(trocar)
// effect 0
// render {count: 0}
Application.clique()
Application=My reaction.do(trocar)
// Effect 1
// render {count: 1}
Application.No()
Application=My reaction.do(trocar)
// // no effect done
// render {count: 1}
Application.clique()
Application=My reaction.do(trocar)
// effect 2
// render {count: 2}

To keep track of dependencies (fromuse effectruns again when dependencies change), we introduce another variable to track_deps.

It's not magic, just matrices.

We have a very good clone of her.useStatemiuse effectfunctionality, but both are poorly implementedsongs(can only be one at a time or errors may occur). To do anything interesting (and allow the last final example to be deprecated), we need to generalize them to get any number of states and effects. Fortunately, howRudi Yardley wrote, React Hooks are not magic, just arrays. so we have aHookLine. We will also take the opportunity to detail_valmi_depsin ourHookArray since they never overlap:

// Example 4
untilMy reaction= (function() {
to allowHook= [],
current hook= 0 // array of hooks and an iterator!
go back {
do(Components) {
untilcourtesy= Components() // Run effects
courtesy.do()
current hook= 0 // reset for next render
go backcourtesy
},
use effect(call back,depArray) {
untildoes not have deps= !depArray
untilabout=Hook[current hook] // Type: Array | undefined
untilhas changedDeps=about? !depArray.one((Y,UE) =>Y===about[UE]) : TRUE
Se (does not have deps||has changedDeps) {
call back()
Hook[current hook] =depArray
}
current hook++ // done with this hook
},
useState(original values) {
Hook[current hook] =Hook[current hook] ||original values// type: any
untilsetStateHookIndex=current hook// to complete setState!
until setstate = new condition => (Hook[setStateHookIndex] =new condition)
go back [Hook[current hook++],setstate]
}
}
})()

Please note our use ofsetStateHookIndexhere this doesn't seem to do anything, but is used to avoidsetstateto close in thecurrent hookVariable! if you take it offsetstateit stopped working again because the closedcurrent hookit's outdated. (Attempt!)

(Video) How do React Hooks really work? Let's build useState from scratch!

// Continuation of example 4 - in use
function trocar() {
until [say,setAccount] =My reaction.useState(0)
until [Text,insert text] =My reaction.useState('Foo') // Hook not 2nd state!
My reaction.use effect(() => {
console.Protocol('It's done',say,Text)
}, [say,Text])
go back {
clique: () => setAccount(say+ 1),
Type: TXT => insert text(TXT),
No: () => setAccount(say),
do: () =>console.Protocol('do', {say,Text})
}
}
to allowApplication
Application=My reaction.do(trocar)
// Effect 0 foo
// represent {count: 0, text: 'foo'}
Application.clique()
Application=My reaction.do(trocar)
// Effect 1 foo
// represent {count: 1, text: 'foo'}
Application.Type('Bar')
Application=My reaction.do(trocar)
// Power 1 bar
// render { count: 1, text: 'bar'}
Application.No()
Application=My reaction.do(trocar)
// // no effect done
// render { count: 1, text: 'bar'}
Application.clique()
Application=My reaction.do(trocar)
// 2 bar effect
// render {count: 2, text: 'bar'}

So the basic intuition is to have a set ofHookand an index that is simply incremented as each link is called and reset when the component is processed.

you can toocustom hookfree:

// Example 4, revised
function Components() {
until [Text,insert text] = useSplitURL('www.netlify.com')
go back {
Type: TXT => insert text(TXT),
do: () =>console.Protocol({Text})
}
}
function useSplitURL(Calle) {
until [Text,insert text] =My reaction.useState(Calle)
untilmasked=Text.divisions('.')
go back [masked,insert text]
}
to allowApplication
Application=My reaction.do(Components)
// { texto: [ 'www', 'netlify', 'com' ] }
Application.Type('www.reactjs.org')
Application=My reaction.do(Components)
// { text: [ 'www', 'reactjs', 'org' ] }}

This really explains how "non-magical" hooks are- Custom hooks simply come off of the primitives provided by the framework, be it React or the little clone we built.

Derivation of hook rules

Note that from here you can understand the first of the trivialhook rules:Call only top level hooks. We explicitly model React's call order dependency with ourcurrent hookVariable. You can readexplanation of all ruleslooking at our implementation and understanding everything that is going on.

Also note that the second rule "Just call hooks from React functions' is also not a necessary result of our implementation, but it's certainly good practice to explicitly delineate which parts of your code depend on stateful logic. (As a nice side effect, it also makes it easier to write tools to ensure that you follow the first rule. You can't accidentally shoot yourself in the foot using stateful functions named like regular JavaScript functions in loops and conditional include. Following rule 2 will give you will help you follow Rule 1.)

Diploma

At this point, we have probably extended the exercise as much as possible. you can tryImplementing useRef as a single line, oactually get the render function to take the JSX and assemble it into the DOM, or a million other important details we left out in this little 28-line React Hooks clone. But I hope you've gained some experience using closures in context and gained a useful mental model that demystifies how react hooks work.

I want to thankE AbramovmiDivya Sasidharanfor reviewing early drafts of this essay and improving it with your valuable comments. All remaining errors are mine.

(Video) A Deep Dive into React Hooks

FAQs

How do React Hooks actually work? ›

Hooks are new React APIs added to React 16.8. They enable React functional components to use React features that were previously only available in React class components. In a nutshell, they are functions that bring the power of React class components to functional components, giving you a cleaner way to combine them.

How does deep dive React work? ›

It renders React components to the DOM and this exact package is available as react-dom npm package. It interacts with React Native implementation, which renders React components to native views.

How do React Hooks really work under the hood? ›

It works by: Checking if the current index has a value in the state, if not set the default. Then build the setter for the current state index value. Finally increment the index (for the next Hook) and return the setter and current value.

Are React Hooks worth it? ›

Hooks make React so much better because you have simpler code that implements similar functionalities faster and more effectively. You can also implement React state and lifecycle methods without writing classes. Below are code examples to illustrate React class and functional components.

What are React hooks in layman's terms? ›

Hooks are just regular JavaScript functions. In layman terms, hooks provide a way to use functionalities such as context or state, which could earlier only be achieved through classes, and now can easily be done using function components.

Is React hooks better than redux? ›

Redux and React Hooks should be viewed as both complementary and distinct concepts. Redux can be used to assist you manage the application data in projects of greater complexity, even though the new React Hooks additions useContext and useReducer allow you to control the global state.

What happens if you don't decompress after a deep dive? ›

Commonly referred to as the bends, caisson disease, or divers sickness / disease, decompression sickness or DCS is what happens to divers when nitrogen bubbles build up in the body and are not properly dissolved before resurfacing, leading to symptoms such as joint pain, dizziness, extreme fatigue, paralysis, and ...

Do deep dives scale with players? ›

Deep dives will scale to player numbers when they start, but due to the fixed difficulty it will likely feel harder than usual.

How deep can you dive without worrying about decompression? ›

Therefore, 140 feet (130 feet for recreational diving) is technically how deep you can dive without decompression. As always, proper training and remaining well within your limits help promote safe diving practices and decrease your risk of decompression sickness.

Do hooks run on every render? ›

Yes! By default, it runs both after the first render and after every update.

Are React hooks still used? ›

React hooks have been around for some time now, yet many React developers are not actively using them. I see two primary reasons behind this. The first reason is that many React developers are already involved in a large project, which requires a significant effort to migrate the entire codebase.

How do you practice React hooks? ›

Best Practices With React Hooks
  1. Only Call Hooks From React Functions. You should only call React Hooks from React functions. ...
  2. Use Only One useEffect Hook. If you're using the useEffect hook, you should only use one per component. ...
  3. Use Hooks at the Top Level. ...
  4. Don't Overuse Hooks.
Oct 25, 2022

What is the downside of React hooks? ›

Hooking functions is the biggest problem of React's approach to state-of-the-box. Hooked functions are hard to reuse and don't offer a way to “attach a reusable behavior to a reusable state', leaving the state out of the box.

What are the disadvantages of hooks? ›

Hooks make it easy to extract logic and they make it easy to reuse it. While using class components, it is possible to share code between components which makes it much more troublesome. Unfortunately, they don't allow us to mix old classes of components with themselves.

When should you not use hooks? ›

Don't call Hooks inside loops, conditions, or nested functions. Instead, always use Hooks at the top level of your React function, before any early returns. By following this rule, you ensure that Hooks are called in the same order each time a component renders.

Are React Hooks still used? ›

React hooks have been around for some time now, yet many React developers are not actively using them. I see two primary reasons behind this. The first reason is that many React developers are already involved in a large project, which requires a significant effort to migrate the entire codebase.

Are React Hooks difficult? ›

React hooks are a constant source of difficult to write and non-deterministic tests. Class components also suffer from the same problems. Now after learning about it I'll never go back to class components. Those aren't the only two options.

Why React Hooks are better than classes? ›

Hooks allow you to use local state and other React features without writing a class. Hooks are special functions that let you “hook onto” React state and lifecycle features inside function components. Important: React internally can't keep track of hooks that run out of order.

How does useState hook work internally? ›

Hooks don't work inside classes — they let you use React without classes. States forms the heart and soul which makes React a go-to library for ease of use and smooth user experience. With function components, there comes a hook known as useState which enables you to define an internal state of a functional component.

Will React Hooks replace classes? ›

Starting with version 16.8, React provides a way to use component and global state without the need for class components. This does not mean that Hooks are a replacement for class components, though.

What is the main advantage of React Hooks? ›

For React developers, Hooks convey ample benefits as follows: It revolutionizes the way you write components. You can write concise and clearer code. Hooks are simpler to work with and test.

What problem does React Hooks solve? ›

Hooks give power to React functional components, making it possible to develop an entire application with it. The aforementioned problems of class components are connected and solving one without the other could introduce further problems.

Videos

1. 10 React Hooks Explained // Plus Build your own from Scratch
(Fireship)
2. How Does React State Actually Work? React.js Deep Dive #4
(Philip Fabianek)
3. React's useState deep dive in 30 minutes
(Scott Batson)
4. React Hooks Deep Dive
(Simpat Tech)
5. Modern React Tutorials - React useEffect hook deep dive
(Code With Sandip)
6. Deep Dive into useEffect Hook in React JS
(CodeWithVishal)

References

Top Articles
Latest Posts
Article information

Author: Lilliana Bartoletti

Last Updated: 16/09/2023

Views: 5925

Rating: 4.2 / 5 (53 voted)

Reviews: 92% of readers found this page helpful

Author information

Name: Lilliana Bartoletti

Birthday: 1999-11-18

Address: 58866 Tricia Spurs, North Melvinberg, HI 91346-3774

Phone: +50616620367928

Job: Real-Estate Liaison

Hobby: Graffiti, Astronomy, Handball, Magic, Origami, Fashion, Foreign language learning

Introduction: My name is Lilliana Bartoletti, I am a adventurous, pleasant, shiny, beautiful, handsome, zealous, tasty person who loves writing and wants to share my knowledge and understanding with you.