Search icon CANCEL
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Designing React Hooks the Right Way
Designing React Hooks the Right Way

Designing React Hooks the Right Way: Explore design techniques and solutions to debunk the myths about adopting states using React Hooks

eBook
€17.99 €26.99
Paperback
€32.99
Subscription
Free Trial
Renews at €18.99p/m

What do you get with Print?

Product feature icon Instant access to your digital eBook copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
Product feature icon AI Assistant (beta) to help accelerate your learning
Table of content icon View table of contents Preview book icon Preview Book

Designing React Hooks the Right Way

Chapter 2: Crafting States in Functions

In the previous chapter, we learned how to write function components in React. In this chapter, we will craft a special variable called a state in the function components. We will see what benefits a state can bring us, including requesting a new update, making a variable persistent, listening to a value change, as well as performing tasks upon the mount. We will also see an example of applying a state to a single-page application. In the end, we will look closely at what role the states play within the UI.

We will cover the following topics in this chapter:

  • Crafting a state in a function component
  • Applying states to single-page applications
  • How states work with UIs
  • Questions and answers

Technical requirements

Before beginning, I would like you to know about the timeline sketch:

|--x---x---x-x--x--x------> user event

The timeline sketch is a unique illustrative chart type that displays a series of events during a period. The left bar (|) stands for the time origin, representing the first update. The horizontal dash (-) moves with the time from left to right with an arrow > at the end. Each letter or number, such as x , indicates one event that happened in this timeline. In this book, we will use the timeline sketch to better understand a situation when multiple things happen simultaneously along the timeline.

Crafting a state in a function component

When you visit a typical web page, it asks for your username and password. After you log in, it displays the content of what the website provides, such as blogs, tweets, or videos, in a chronological order. You can vote on them and put your comments there – a very typical web experience these days.

When you surf a website like that as a user, you don't put too much thought into how any of the actions are implemented, nor do you care about the order in which each is fired. However, when it comes to building the site yourself, each action and the time at which each gets fired starts to become important.

An action handler fires when a user clicks a button, hovers over an icon, scrolls down a paragraph, types on the keyboard, and so on. A typical relationship between a user event and an action handler is illustrated in the following:

|--x---x---x-x--x--x------> user event
|--a---a---a-a--a--a------> action handler

In the preceding sketch, basically, an x in the user event series is followed by an a in the user event series. Based on this, we can start to handle a user action.

Let's turn ourselves to a "Hello World" Title component with a button inside. Each time we click the button, a counter gets incremented by one and appended after Hello World+, as shown in Figure 2.1:

Figure 2.1 – Hello World with no state

Figure 2.1 – Hello World with no state

To implement that, we start with a count variable to store a number initialized as 0:

function Title() {
  let count = 0  
  const onClick = () => {
    count = count + 1
  }
  return (
    <>
      <button onClick={onClick}>+</button>
      <h1>Hello World+{count}</h1>
    </>
  )
}

In the preceding Title component, the response to the user click is implemented via a React event handler, onClick, wired to a button element.

A React event handler is written slightly differently from a DOM event handler. You can tell from the onClick camel case name, rather than the onclick lowercase name. A React event is a synthetic event that is a cross-browser wrapper around the browser native event. In this book, we expect them to behave in exactly the same way.

Thanks to the JavaScript closure, we can directly access any component variable inside the event handler. The count variable does not need to be passed into onClick as a function input argument to be accessed.

If we run the code, we'd expect the title to display Hello World+1 after we click the button. But to our surprise, no matter how many times we clicked the button, it still displayed Hello World+0. To figure out what happened, let's add console.log to two locations.

One is placed before count = count + 1 to confirm what the count is after incrementation. Another one is placed before the return statement to confirm what the updated count is when the Title component is updated. They are marked at and ➁ in the following code:

function Title() {
  let count = 0
  const onClick = () => {
    console.log('clicked', count)      ➀
    count = count + 1
  }
  console.log('updated', count)        ➁
  return ...
}

With these two logs placed, we can rerun the code and generate a new timeline sketch:

|----0--1-2--3-4----5------> clicked   ➀
0--------------------------> updated   ➁

From the preceding printout, a clicked series at ➀ showed the count number when the button was clicked, and it was clicked six times. Let's turn to another log, the updated series at ➁; the count value got updated once as 0, which explains why the display remained as Hello World+0.

The updated series with only one printout at the very beginning indicates that there weren't any more updates after the first one. This is quite a discovery. If there were no more updates, how can we expect to see a change on the screen?

Playground – No State

Feel free to play with this example online at https://codepen.io/windmaomao/pen/jOLNXzO.

As you might already realize, we need to request a new update after the click.

Requesting a new update

To make an update, for the time being, we can borrow the render function provided by React, as we have already used it to update the rootEl element:

ReactDOM.render(<Title />, rootEl)

Let's take a minute to see how React updates the screen in general (see Figure 2.2). The detail involving updates can be quite complex; for now, let's treat it as a black box. We will get into more details later in the book:

Figure 2.2 – React update

Figure 2.2 – React update

When an app starts, it lands on an update. This first update is a bit special. Because all the DOM elements need to be created, we refer to this update as a mount.

What's important to know is that a new update wouldn't arrive unless it's requested, just as we invoke a render function. When people first come to React, they might think it works as a game engine.

For instance, a game engine would request a new update every 1/60 second behind the scenes. But React does not do that! Instead, the developer should get precise control of when a new update is requested. And most of the time, the frequency is a lot lower than 1/60 second, and it's more or less driven by how fast a user acts on the website.

So with this, to bring the new count to the screen, another update needs to be requested manually; if we borrow the render, we can use it after the count is incremented:

  const onClick = () => {
    console.log('clicked', count)      ➀
    count = count + 1
    ReactDOM.render(<Title />, rootEl)
  }

If we run the preceding code with the addition of render, the timeline sketch changes to the following:

|----0--0-0--0-0----0------> clicked   ➀
0----0--0-0--0-0----0------> updated   ➁

To our surprise, all numbers displayed were 0. Looking at the updated series at , note we got seven printouts, which means we got six more updates on top of the first update. However, the clicked series at shows that the count value changed to 0 and stopped to increment any more. Weird?!

How could the count value be stuck at 0? Something must happen to the new update, but the render function can't be the one that resets the count value back to 0, can it?

It's important to know that upon the render function being called and a function component being updated, the function that defines the component gets invoked, as shown in Figure 2.3:

Figure 2.3 – React render for a function component

Figure 2.3 – React render for a function component

With this knowledge, let's take a look at the Title function again:

const Title = () => {
  let count = 0
  // omitting the onClick statement
  console.log('updated', count)       ➁
  // omitting the return statement
}

In the preceding code, we intentionally omit the onClick and return statements to make the code a bit cleaner. What was left became a let count = 0 declaration statement. During each update, the Title function gets invoked, thus creating a new scope of the function. Inside this scope, there's a variable count value created locally to hold a 0 number. So this code doesn't seem to do much.

It's not too difficult to see now why the count value remains at 0, isn't it? It doesn't really matter if we have added the increment logic onClick or return statement. Upon each update, the entire function scope gets a new one with a count value declared and set to 0. That explains why the console.log statement followed a printed 0.

This is actually the reason why a function component was named as a stateless function when it was introduced to React initially. "Stateless" refers to the fact that a function component can't carry or share a value to another update. In a simple word, the function reruns in each update with the same output.

Okay, now we understand the problem. So, it makes us consider saving the count value somewhere and making it persistent for another update.

Making a value persistent

JavaScript supports a function scope: Variables defined inside a function cannot be accessed from anywhere outside the function, thus each function has its own scope. If you invoke a function multiple times, there'll be multiple scopes. But no matter how many times we invoke it, it wouldn't create a different output, such as what happened in the movie Groundhog Day.

Note

The movie Groundhog Day is a 1993 fantasy comedy film, where Phil wakes up every day to find he experiences the previous day's events repeating exactly and believes he is experiencing déjà vu.

For our count value, we can visualize what happened with the two updates in two different scopes in Figure 2.4:

Figure 2.4 – Two function scopes for the two updates

Figure 2.4 – Two function scopes for the two updates

Luckily, JavaScript supports a function scope in a way that it can access all variables defined inside the scope in which it is defined. In our case, if a variable is defined outside of the Title function, we can access this variable inside the Title functions, as this value is shared now between multiple Title functions.

The easiest way of sharing is to create a global variable because the global variable lives in the most outer scope of the JavaScript code, thus it can be accessed inside any function.

Note

Don't be intimidated by a global variable used in this chapter. In Chapter 3, Hooking into React, we will refine this approach and see how React defines the variable in a better location.

This way, each local count value can set/get this global count value, as shown in Figure 2.5:

Figure 2.5 – A shared value among the two updates

Figure 2.5 – A shared value among the two updates

Okay, with this new global variable idea, let's see whether we can break out of our Groundhog Day situation:

let m = undefined
function _getM(initialValue) {
  if (m === undefined) {
    m = initialValue
  }
  return m
}
function _setM(value) { 
  m = value
  ReactDOM.render(<Title />, rootEl)
}

In the preceding code, a global variable, m, is allocated, and it comes with _getM getter and _setM setter methods. The _getM function returns the value but sets the initial value for the first time. The _setM function sets the value and requests a new update. Let's apply _getM and _setM to our Title component:

function Title() {
  let count = _getM(0) 
  const onClick = () => {
    console.log('clicked', count)      ➀
    count = count + 1
    _setM(count)
  }
  console.log('updated', count)         ➁
  return ...
}

Inside the preceding amended Title component, all count variables across updates are linked with the help of _getM and _setM. If we rerun the code, we can see the following timeline sketch:

|----0--1-2--3-4----5------> clicked   ➀
0----1--2-3--4-5----6------> updated   ➁

Wow! The screen changes to Hello World+1 upon the first click and increments further upon more clicks, as shown in Figure 2.6:

Figure 2.6 – Hello World counter using a state

Figure 2.6 – Hello World counter using a state

Congratulations! You just crafted a state inside a function component.

Playground – Count State

Feel free to play with this example online at https://codepen.io/windmaomao/pen/KKvPJdg.

The word "state" refers to the fact that it's persisted for all updates. For our convenience, we also change the state and request a new update afterward to reflect the change to the screen.

So, now we know how to handle a user action with a state. Let's see whether we can expand this idea further to support multiple states instead of one state.

Support multiple states

It's great that we can establish a state persistent within a function component. But we want more states like that. An app normally contains lots of buttons, switches, and actionable items; each requires a state to be persistent. So, it's a must-have to support multiple states in the same app.

So, say we need two buttons and each needs to be driven by a state. Let's extend what we have learned from a single state:

const Title = () => {
  let countH = _getM(0)
  let countW = _getM(0)
  const onClickH = () => {
    countH = countH + 1
    _setM(countH)
  }
  const onClickW = () => {
    countW = countW + 1
    _setM(countW)
  }
  return (
    <>
      <button onClick={onClickH}>+</button>
      <h1>Hello+{countH}</h1>
      <button onClick={onClickW}>+</button>
      <h1>World+{countW}</h1>
    </>
  )
}

In the preceding code, we first created two buttons, one with a Hello label and one with a World label, and each have their separate event handler, onC1ickH and onClickW respectively. Also, we applied _getM and _setM to both of them, and installed a couple of logs to help the debug, as shown in the following timeline sketch:

|----0--1-2----------------> clickedH   
|------------3-4----5------> clickedW   
0----1--2-3--4-5----6------> updatedH   
0----1--2-3--4-5----6------> updatedW   

From the preceding sketch, we clicked the Hello button three times and then clicked the World button three times. The numbers corresponding to both buttons all updated upon clicking, as shown in the updatedH and updatedW series. However, the two series seem to be inseparable and in sync, meaning clicking one button would increment both values at the same time!

Playground – Linked States

Feel free to play with this example online at https://codepen.io/windmaomao/pen/qBXWgay.

Okay, it's not too difficult to find out that we actually made a mistake by wiring the same state to both buttons; no wonder they updated at the same time:

  let countH = _getM(0)
  let countW = _getM(0)

Although this is not what we wanted to achieve, it's interesting to see that a state is shared by two buttons. Visually, we linked two buttons; clicking one triggers the click on another.

So, what can we do if we want to have two separate states with each controlling one button? Well, we can just add another state. This time, we want to be a bit more generic in using a list to hold any number of states.

There are lots of ways to keep track of a list of values in JavaScript; one of the ways is to use a key/value pair, as in an object:

let states = {}
function _getM2(initialValue, key) {
  if (states[key] === undefined) {
    states[key] = initialValue
  }
  return states[key]
}
function _setM2(v, key) {
  states[key] = v
  ReactDOM.render(<Title />, rootEl)
}

In the preceding code, we declare a states object to store all state values. The _getM2 and _setM2 functions are almost similar to the single-value version we crafted earlier, except this time we store each state under states[key] instead of m, thus a key is needed to identify each state. With this change, let's amend the Title component:

function Title() {
  let countH = _getM2(0, 'H')
  let countW = _getM2(0, 'W')
  const onClickH = () => {
    console.log('clickedH', countH)     
    countH = countH + 1
    _setM2(countH, 'H')
  }
  const onClickW = () => {
    console.log('clickedW', countW)     
    countW = countW + 1
    _setM2(countW, 'W')
  }
  console.log('updatedH', countH)         
  console.log('updatedW', countW)          
  return ...
}

In the preceding amended version, we give a key to two states as H and W. We need this key for both set and get when a state is involved. Rerun the code and take a look at the timeline sketch:

|----0--1-2----------------> clickedH  
|------------0-1----2------> clickedW  
0----1--2-3--3-3----3------> updatedH  
0----0--0-0--1-2----3------> updatedW  

Once again, we clicked the Hello button three times and World button three times in a row. The numbers on both buttons all updated upon clicking, but this time, countH and countW are actually incremented separately, as you can see in the updatedH and updatedW series.

After the first three clicks on the Hello button, countH stays at 3 when we click on the World button. This is what we want to have, two separate states, as shown in Figure 2.7:

Figure 2.7 – Hello and World buttons with two states

Figure 2.7 – Hello and World buttons with two states

Playground – Multiple States

Feel free to play with this example online at https://codepen.io/windmaomao/pen/dyzbaVr.

The state we crafted so far requests a new update. This is a very good use of persistency in a function component; since being persistent is actually quite a generic feature, it should be utilized for many different purposes. So, what other things can we do with it? Let's take a look at another usage of a state.

Listen to a value change

You might wonder why we need to listen to a value change. Aren't the developers the ones who control the change of a value? As in the previous example, we use the event handler to change a counter. We know in this case exactly when the value gets changed.

That's true for this case, but there are other cases. You might send a value into a child component via a prop, or there might be two components that touch a value at the same time. In either of these cases, you can lose track of the moment when the value is changed, but you still want to perform an action upon the value change. This means that you want to have the ability to listen to a value change. Let's set up one example to demonstrate this.

Say in our Hello World button example that for any count change, we want to know whether this value has recently been changed:

function Changed({ count }) {
  let flag = 'N'
  return <span>{flag}</span>
}

In the preceding Changed component, there's a count prop that is sent from its parent, say any of the Hello or World buttons that we built earlier. We want to display Y or N, depending on whether the count value has changed. We can use this Changed component in the Title component:

function Title() {
  ...
  return (
    <>
      <button onClick={onClickH}>+</button>
      <h1>Hello+{countH}</h1>
      <Changed count={countH} />
      <button onClick={onClickW}>+</button>
      <h1>World+{countW}</h1>
    </>
  )
}

Note that in the preceding code, we add the Changed component between two buttons, and what we want to see is the Changed component display Y when we click the Hello button, and the Changed component display N when we click on the World button. Essentially, we want to know whether the change is coming from the Hello button or not. But when we ran the code, here's what we got in the timeline sketch:

0----1--2-3--3-3----3------> updatedH   
0----0--0-0--1-2----3------> updatedW   
N----N--N-N--N-N----N------> Changed flag

From the preceding sketch, you can see that no matter which button is clicked, the flag in the Changed flag series displayed N. This comes as no surprise, since you might have already noticed that the flag inside the Changed component is fixed at N, so it wouldn't work the way we wanted. But the reason we wrote N there is because we don't know what to write there to flip the flag.

When the Hello button gets clicked three times, the countH value, as in the updatedH series, increments to 3. Similarly, when the World button gets the next three clicks, the countW value, as in the updatedW series, increments to 3. However, note that as the countW value increments, the countH value also gets printed out; see 3-3-3 in the updatedH series.

This indicates that for each update, every element under the return statement gets updated. Either countW or countH changes; it comes to a new update of the Title component, thus updating all button and h1 elements. The same applies to the Changed component; whichever button changes, the Changed function gets invoked. Therefore, we can't tell whether the update to the Changed component is due to the Hello button or the World button.

If we print out the count prop under the Changed component, it will look the same as in the updatedH series:

0----1--2-3--3-3----3------> count

Looking at the preceding count value, in order to come up with the changed flag for whether it changes from the previous value, we need to make a value persistent again – in this case, to get hold of the previous value. For example, 0 to 1 is a change, but 3 to 3 isn't.

Okay, to put this idea to work, let's borrow the state approach but this time apply it to a prev value:

let prev
function _onM(callback, value) {
  if (value === prev) return 
  callback()
  prev = value
}

In the preceding code, we allocated a prev global variable and a _onM utility function. The onM function is designed to run a callback function when the value changes. It first checks whether the value is equal to the prev value. It returns if there's no change. But if there is, the callback function is then invoked, and the current value replaces the prev value. Let's apply this _onM function to the Changed component:

function Changed({ count }) {
  let flag = 'N'
  _onM(() => { flag = 'Y' }, count)
  return <span>{flag}</span>
}

With the preceding change, we rerun the code and take a look at the updated timeline sketch:

0----1--2-3--3-3----3------> updatedH 
0----0--0-0--1-2----3------> updatedW 
Y----Y--Y-Y--N-N----N------> Changed flag

Interestingly enough, when we clicked the Hello button this time, it displayed Y, and when we clicked the World button afterward, it changed to N, as shown in Figure 2.8:

Figure 2.8 – Listen to value change

Figure 2.8 – Listen to value change

Wonderful! Also, notice the first Y at the mount in the Changed flag series, which is when countH changes from undefined to 0. Please make a note here; we'll talk about it in the next section.

Playground – Listening to State Change

Feel free to play with this example online at https://codepen.io/windmaomao/pen/MWvgxLR.

Being able to listen to a value change is quite useful because it provides us with another way to perform tasks. Without it, we have to rely on an event handler, which is mostly driven by user actions. With _onM, we can perform a task upon a value change, which can come out of any other process.

When listening to a value change, there exists a moment at the mount. This means that we can perform a task at the mount because of it. Let's take a look at it more closely.

Performing a task at the mount

Components mount and un-mount as things show up and disappear based on the business requirement. At the mount, it's common to want to perform a task such as initializing some variables, calculating some formulas, or fetching an API to get some resources over the internet. Let's use an API call as an example.

Say a count value needs to be fetched from an online service called /giveMeANumber. When this fetch returns successfully, we would like to reflect the change to the screen:

fetch('/giveMeANumber').then(res => {
  ReactDOM.render(<Title />, rootEl)
})

The preceding code is what we'd like to do; however, we run into a technical issue right away. Though a new update can be requested, how can we send the returned data to the Title component?

Maybe we can set up a prop on the Title component to send it in. However, doing that would require us to change the component interface. Since we already have had states crafted to issue a new update, let's try that approach:

fetch('./giveMeANumber').then(res => {
  _setM(res.data)
})
function Title() => {
  const count = _getM("")    
  return <h1>{count}</h1>
}

In the preceding code, by using _setM after the fetch returns, we can update a state with the received res.data and request a new update afterward. The new update invokes Title and reads the latest count from the state via _getM.

Currently, we define the fetch function parallel to the Title component, but this is not the right location since we want to fetch only at the mount. To fix that, we can listen to the mount, as we have learned in the previous section:

 _onM(() => { ... }, 0)

Using the preceding line, we can listen for a mount moment. Note that we watched a constant 0 instead of any variable. During the mount, the value that _onM listens to changes from undefined to 0, but for other future updates, the value stays at 0; therefore, the ... callback gets invoked only once at the mount. Let's write fetch inside this callback:

function Title() => {
  const count = _getM(0)
  _onM(() => {
     fetch('./giveMeANumber').then(res => {
       _setM(res.data)
     })
  }, 0) 
  console.log('u')
  return <h1>{count}</h1>
}

If we run the preceding code, the timeline sketch should generate the following:

u-----u-------------------> log

At the mount of the Title component, the count state is set to be 0 initially. A fetch function is performed right away, depicted as the first u in the preceding updates series. Only when fetch returns successfully does the count state get updated to a new value and refreshed to the screen. The new update is depicted as the second u in the updates series.

Playground – Task at Mount

Feel free to play with this example online at https://codepen.io/windmaomao/pen/PoKobVZ.

Between the first and the second update, that's how long it takes for the API to finish. The relationship between the API, the state, and two updates is illustrated in Figure 2.9. Essentially, after the API returns, it communicates to the shared state where the new update picks up later:

Figure 2.9 – Fetch API within the stateful component

Figure 2.9 – Fetch API within the stateful component

Now that we have crafted a state, and also seen how flexible a state can be used to either make a new update or listen to a value change, let's get hands-on and apply what we have learned to an app.

Applying states to single-page application

We want to continue what we started in the previous chapter in building a single-page application. We couldn't finish it back then because we lacked a way to switch to a different page other than the home page. We had put together a Nav component:

const Nav = ({ items, selected }) => { ... }

Given a list of pages, the Nav component displays them as links to navigate. The currently selected page needs to be provided as well. Now that we know how to define a state, let's use it to keep track of the selected page:

const App = () => {
  const selected = _getM("home") 
  return ( 
    <div>
      <Nav
        items={menus}
        selected={selected}
        onSelect={_setM}
      />
      ...
    </div>
  )
}

In the preceding App component, we used a state for selected to hold the home key initially, which is then passed into the Nav component. To allow the state to be updated after a user click, we need to modify Nav by adding the support of an onSelect callback function:

const Nav = ({ items, selected, onSelect }) => {
  const isActive = item => item.key === selected
  const onClick = item => () => { 
    onSelect(item.key)
  }
  ...
}

In the preceding amended Nav component, an onSelect prop is passed so that after onClick, the parent App component can be notified to update the selected page via the _setM function.

To confirm that the user does reach a different page, based on the current selected page, we can use a Route component to switch between page content:

const Route = ({ selected }) => {
     return (
       <div>
      {selected === 'home' && <Home />}
      {selected === 'product' && <Product />}
    </div>
     )
}

What the preceding Route component does is display the page content based on the selected page. Note that it uses a && symbol, which is a common line in React code. It's equivalent to the following:

      {selected === 'home' ? <Home /> : false}

If the condition matches on the left part, it returns <Home />; otherwise, it returns false. And according to React, any true, false, null, or undefined values are all valid elements, but when updated, they all get ignored without being displayed. Essentially, if the left part condition doesn't meet, it displays nothing.

Putting the Nav and Route components together, we can amend the App component:

const Home = () => <h1>Home page</h1>
const Product = () => <h1>Product page</h1>
const App = () => {
  const selected = _getM("home")  
  return ( 
    <div>
      <Nav
        items={menus} 
        selected={selected} 
        onSelect={_setM} 
      />
      <Routes selected={selected} />
    </div>
  )
}

Finally, we got two pages working, as shown in Figure 2.10! If you click the Product link, it'll land on the product page:

Figure 2.10 – A single-page application using a state

Figure 2.10 – A single-page application using a state

To recap, the App component defines a selected state to hold the currently selected page. The Nav component is used to display all the links and allow it to choose a different page by clicking on the link. The Route component is used to display a page based on the selected state. Essentially, based on this setup, adding more pages is just a matter of adding new components under the Route component.

Playground – Single-Page Application

Feel free to play with this example online at https://codepen.io/windmaomao/pen/PoKoWPG.

Before we end this chapter, let's take a minute to look at how exactly a state drives the UI under React.

How states work with UI

With the introduction of state to the function component, we sometimes can get dizzy by the roles that it plays. We will use three components to elaborate, as shown in Figure 2.11:

Figure 2.11 – Props in components

Figure 2.11 – Props in components

We have three components depicted in solid boxes. The outer component contains the middle one as a child, and the middle one contains the inner one as a child. Props, depicted as arrow lines crossing the boundary of a solid box, pass values from a parent to a child component.

React is a state machine. For a given fixed set of variables, it paints the screen the same way. With props, this is quite straightforward since each component is solely determined by its props. Now, let's add the states to the picture, as shown in Figure 2.12. States, depicted as a symbol with a circle and a dot, are defined inside each component:

Figure 2.12 – States and props in components

Figure 2.12 – States and props in components

Taking the C inner component first, it doesn't have any state defined. So, it's still determined by its props.

The B middle component has one state defined. With a fixed set of its props, the screen corresponding to the component still can vary because this state can take a different value on each update.

The A outer component has two states defined. Similarly, with all its props fixed, the screen corresponding to it can still vary. The variation can come from any of its two states, and it can come from the state of the B component as well because the states of the parent and the child can work independently upon updates.

Therefore, we can conclude that to get the screen painted for the A component, we need to fix all props and states within itself and all its child components underneath. This is not a mathematical theory, but given the states from multiple components, this observation is apparent.

In short, props and states now both serve as the input of the component. The states can be especially vibrant since their values can be, but are not always, wired with an external system. The external system can be browser events or the API fetch, or anything else. Because a state can send to a child component via a prop, the effect of the state can cascade down deep into the app tree quickly.

Summary

In this chapter, we started to craft a new thing called a state inside the function component. The state is persistent across updates and can be used to request a new update, listen to a value change, as well as perform a task at the mount. Later, we applied the state we developed to a single-page application to draft a simplified Nav with a route system. In the end, we briefly studied how states work for UI under React.

In the next chapter, we will introduce you to what a React hook is and how this persistent state is designed under the React engine.

Questions and answers

Here are some questions and answers to refresh your knowledge:

  1. What is a state?

    For a function component, a state is a value created to be persistent during the life of the component. From each update, including the mount, this value can be accessed from inside a function.

  2. What are the usages of states?

    If a task can't be done within one update, that is the time we can think of using a state to reference a memory that can be accessed in multiple updates. We normally use a state to request a new update, listen to a value change, as well as perform a task at the mount. But the states can be very versatile.

  3. What does a state do to the UI?

    To determine the screen corresponding to a component, we need to know its states as well as its props. While the props are passively defined on the component interface, the states are defined inside the component to actively refine its behavior. Apps built with states can change with time, driven by either user interactions or any other external processes.

Left arrow icon Right arrow icon

Key benefits

  • Get to grips with Hooks' design and understand each built-in Hook's pitfalls with examples
  • Discover how to turn your existing code into a reusable Hook via code refactoring
  • Explore design solutions to identify and solve site performance issues involving Hooks

Description

React hook creates a unique solution for using states in function components to orchestrate UI communication. They provide you with an easy interface to write custom data management solutions with low development and maintenance costs. Understanding how Hooks are designed enables you to use them more effectively, and this book helps you to do just that. This book starts with a custom-crafted solution to reveal why Hooks are needed in the first place. You will learn about the React engine and discover how each built-in Hook can manage a persistent value by hooking into it. You will walk through the design and implementation of each hook with code so that you gain a solid understanding. Finally, you'll get to grips with each Hook's pitfalls and find out how to effectively overcome them. By the end of this React book, you'll have gained the confidence to build and write Hooks for developing functional and efficient web applications at scale.

Who is this book for?

This book is for web developers who are looking for a consistent and efficient approach for applying application states with Hooks. Basic knowledge of React will help you to get the most out of this book.

What you will learn

  • Create your own hooks to suit your state management requirement
  • Detect the current window size of your website using useEffect
  • Debounce an action to improve user interface (UI) performance using useMemo
  • Establish a global site configuration using useContext
  • Avoid hard-to-find application memory leaks using useRef
  • Design a simple and effective API data layer using custom Hooks
Estimated delivery fee Deliver to Czechia

Premium delivery 7 - 10 business days

€25.95
(Includes tracking information)

Product Details

Country selected
Publication date, Length, Edition, Language, ISBN-13
Publication date : Jan 11, 2022
Length: 278 pages
Edition : 1st
Language : English
ISBN-13 : 9781803235950
Languages :
Tools :

What do you get with Print?

Product feature icon Instant access to your digital eBook copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
Product feature icon AI Assistant (beta) to help accelerate your learning
Estimated delivery fee Deliver to Czechia

Premium delivery 7 - 10 business days

€25.95
(Includes tracking information)

Product Details

Publication date : Jan 11, 2022
Length: 278 pages
Edition : 1st
Language : English
ISBN-13 : 9781803235950
Languages :
Tools :

Packt Subscriptions

See our plans and pricing
Modal Close icon
€18.99 billed monthly
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Simple pricing, no contract
€189.99 billed annually
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just €5 each
Feature tick icon Exclusive print discounts
€264.99 billed in 18 months
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just €5 each
Feature tick icon Exclusive print discounts

Frequently bought together


Stars icon
Total 97.97
Micro State Management with React Hooks
€27.99
Full-Stack Web Development with GraphQL and React
€36.99
Designing React Hooks the Right Way
€32.99
Total 97.97 Stars icon

Table of Contents

11 Chapters
Chapter 1: Introducing the Function Component Chevron down icon Chevron up icon
Chapter 2: Crafting States in Functions Chevron down icon Chevron up icon
Chapter 3: Hooking into React Chevron down icon Chevron up icon
Chapter 4: Use State to Jumpstart Components Chevron down icon Chevron up icon
Chapter 5: Use Effect to Handle Side Effects Chevron down icon Chevron up icon
Chapter 6: Use Memo to Boost Performance Chevron down icon Chevron up icon
Chapter 7: Use Context to Cover an Area Chevron down icon Chevron up icon
Chapter 8: Use Ref to Hide Stuff Chevron down icon Chevron up icon
Chapter 9: Use Custom Hooks to Reuse Logic Chevron down icon Chevron up icon
Chapter 10: Building a Website with React Chevron down icon Chevron up icon
Other Books You May Enjoy Chevron down icon Chevron up icon

Customer reviews

Top Reviews
Rating distribution
Full star icon Full star icon Full star icon Half star icon Empty star icon 3.4
(7 Ratings)
5 star 42.9%
4 star 14.3%
3 star 0%
2 star 28.6%
1 star 14.3%
Filter icon Filter
Top Reviews

Filter reviews by




subrat22 Jan 26, 2022
Full star icon Full star icon Full star icon Full star icon Full star icon 5
First Neatly explained the concept with respect to JavaScript Then moved to React library .examples are simple and clean , which is good part of this book
Amazon Verified review Amazon
Manikanta kumar Mar 09, 2022
Full star icon Full star icon Full star icon Full star icon Full star icon 5
Completed the first chapter and I’m loving it. Easy to understand and learn/revisit React.
Amazon Verified review Amazon
Amazon Customer Apr 06, 2022
Full star icon Full star icon Full star icon Full star icon Full star icon 5
I recently started working with React again and this book provided a great refresher. It starts by providing a deep dive into the absolute basics of functional components and State, which I defiantly needed! I would highly recommend this book for beginners learning react. The code examples are easy to understand and allowed me to better visual how to create and use these hooks. The book then expands on data structure and usage of each hook in detail. I defiantly love all of the examples within the code as I am a visual learning, making this book very easy to read and understand all the concepts.
Amazon Verified review Amazon
zoha Mar 05, 2022
Full star icon Full star icon Full star icon Full star icon Empty star icon 4
I have recently started working on a React project, and working with React hooks is something new for me. This book begins with a deep dive into the absolute basics of functional components and State. Then goes on to explain the data structure and usage of each hook in detail.Overall the book and the source code it provides are well written. Very helpful for me to understand the usability of each hook. I would highly recommend this book for beginners trying to learn functional components and hooks.I was not too impressed by creating a custom hook section, I think it left out a lot of performance optimization details but if you are a beginner, its a good starting point.
Amazon Verified review Amazon
Paul W Nov 23, 2023
Full star icon Full star icon Empty star icon Empty star icon Empty star icon 2
I was disappointed to learn that the topic of this book isn't really React hooks, but rather how you might implement them if you were reimplementing them. This of course provides insights but what I was looking for in this book was an in-depth discussion of React hooks and how and when to use them.
Amazon Verified review Amazon
Get free access to Packt library with over 7500+ books and video courses for 7 days!
Start Free Trial

FAQs

What is the delivery time and cost of print book? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela
What is custom duty/charge? Chevron down icon Chevron up icon

Customs duty are charges levied on goods when they cross international borders. It is a tax that is imposed on imported goods. These duties are charged by special authorities and bodies created by local governments and are meant to protect local industries, economies, and businesses.

Do I have to pay customs charges for the print book order? Chevron down icon Chevron up icon

The orders shipped to the countries that are listed under EU27 will not bear custom charges. They are paid by Packt as part of the order.

List of EU27 countries: www.gov.uk/eu-eea:

A custom duty or localized taxes may be applicable on the shipment and would be charged by the recipient country outside of the EU27 which should be paid by the customer and these duties are not included in the shipping charges been charged on the order.

How do I know my custom duty charges? Chevron down icon Chevron up icon

The amount of duty payable varies greatly depending on the imported goods, the country of origin and several other factors like the total invoice amount or dimensions like weight, and other such criteria applicable in your country.

For example:

  • If you live in Mexico, and the declared value of your ordered items is over $ 50, for you to receive a package, you will have to pay additional import tax of 19% which will be $ 9.50 to the courier service.
  • Whereas if you live in Turkey, and the declared value of your ordered items is over € 22, for you to receive a package, you will have to pay additional import tax of 18% which will be € 3.96 to the courier service.
How can I cancel my order? Chevron down icon Chevron up icon

Cancellation Policy for Published Printed Books:

You can cancel any order within 1 hour of placing the order. Simply contact customercare@packt.com with your order details or payment transaction id. If your order has already started the shipment process, we will do our best to stop it. However, if it is already on the way to you then when you receive it, you can contact us at customercare@packt.com using the returns and refund process.

Please understand that Packt Publishing cannot provide refunds or cancel any order except for the cases described in our Return Policy (i.e. Packt Publishing agrees to replace your printed book because it arrives damaged or material defect in book), Packt Publishing will not accept returns.

What is your returns and refunds policy? Chevron down icon Chevron up icon

Return Policy:

We want you to be happy with your purchase from Packtpub.com. We will not hassle you with returning print books to us. If the print book you receive from us is incorrect, damaged, doesn't work or is unacceptably late, please contact Customer Relations Team on customercare@packt.com with the order number and issue details as explained below:

  1. If you ordered (eBook, Video or Print Book) incorrectly or accidentally, please contact Customer Relations Team on customercare@packt.com within one hour of placing the order and we will replace/refund you the item cost.
  2. Sadly, if your eBook or Video file is faulty or a fault occurs during the eBook or Video being made available to you, i.e. during download then you should contact Customer Relations Team within 14 days of purchase on customercare@packt.com who will be able to resolve this issue for you.
  3. You will have a choice of replacement or refund of the problem items.(damaged, defective or incorrect)
  4. Once Customer Care Team confirms that you will be refunded, you should receive the refund within 10 to 12 working days.
  5. If you are only requesting a refund of one book from a multiple order, then we will refund you the appropriate single item.
  6. Where the items were shipped under a free shipping offer, there will be no shipping costs to refund.

On the off chance your printed book arrives damaged, with book material defect, contact our Customer Relation Team on customercare@packt.com within 14 days of receipt of the book with appropriate evidence of damage and we will work with you to secure a replacement copy, if necessary. Please note that each printed book you order from us is individually made by Packt's professional book-printing partner which is on a print-on-demand basis.

What tax is charged? Chevron down icon Chevron up icon

Currently, no tax is charged on the purchase of any print book (subject to change based on the laws and regulations). A localized VAT fee is charged only to our European and UK customers on eBooks, Video and subscriptions that they buy. GST is charged to Indian customers for eBooks and video purchases.

What payment methods can I use? Chevron down icon Chevron up icon

You can pay with the following card types:

  1. Visa Debit
  2. Visa Credit
  3. MasterCard
  4. PayPal
What is the delivery time and cost of print books? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela