Learn to use all the common hooks in React, and how to put them to use within your application. Then, build your own custom hooks.
Learning Objectives
- Explain the uses and purpose of React hooks.
- Use the useState hook to declare, read and update the state of a component.
- Use the useEffect hook to perform side-effects within a React component.
- Use hooks to fetch data in React.
- Create appropriate custom hooks in React.
- Getting started with hooks
- Video: Working with React hooks
- Video: Revising useState hook
- Reading: Working with complex data in useState
- Video: Using the useState hook
- Lab: Exercise: Managing state within a component
- Reading: Solution: Managing state within a component
- Step 4
- Practice Quiz: Self-review: Managing state within a component
- Video: What are side effects?
- Reading: What is the useEffect hook?
- Video: Using the useEffect hook
- Practice Quiz: Knowledge check: Getting started with hooks
- Reading: Additional resources
- Rules of Hooks and Fetching Data with Hooks
- Video: What are the rules of hooks?
- Video: What you need to know before fetching data
- Reading: Data fetching using hooks
- Video: Fetching data – Putting it all together
- Fetching data – Putting it all together in React
- Lab: Exercise: Can you fetch data?
- Reading: Solution: Can you fetch data?
- Practice Quiz: Self-review: Can you fetch data?
- Video: APIs
- Practice Quiz: Knowledge check: Rules of Hooks and Fetching Data with Hooks
- Reading: Additional resources
- Advanced hooks
- Video: What is useReducer and how it differs from useState
- Reading: When to choose useReducer vs useState
- Video: useRef to access underlying DOM
- Reading: Custom hooks
- Lab: Exercise: Create your own custom hook, usePrevious
- Reading: Solution: Create your own custom hook, usePrevious
- Practice Quiz: Self-review: Create your own custom hook, usePrevious
- Practice Quiz: Knowledge check: Advanced Hooks
- Video: Module summary: React Hooks and Custom Hooks
- Quiz: Module quiz: React Hooks and Custom Hooks
- Reading: Additional resources
Getting started with hooks
Video: Working with React hooks
Murtadha, a software engineer at Meta, shares his experience with React hooks and why he believes they are a valuable tool for React developers. He explains that hooks were first introduced to a community of React enthusiasts for feedback, and that Meta started using them internally before rolling them out more widely.
Murtadha acknowledges that hooks can be difficult to learn at first, but he encourages developers to stick with it because they can greatly improve the quality of code. He says that hooks can simplify applications, introduce performance gains, make code more readable and easier to manage, and make code more shareable and reusable.
Murtadha’s advice for developers who are learning hooks is to “stick it out.” He says that it may be tempting to use the old way of writing React code, but that hooks are worth the investment in the long run.
Additional thoughts:
Murtadha’s experience with React hooks is similar to that of many other developers. Hooks can be a bit difficult to learn at first, but they offer many benefits once you master them. If you are a React developer, I encourage you to give hooks a try. You may be surprised at how much they can improve your code.
What are React hooks?
React hooks are functions that let you use state and other React features without writing a class. They were introduced in React 16.8 and have quickly become one of the most popular features of the library.
Why use React hooks?
There are a number of reasons why you might want to use React hooks:
- Simplicity: Hooks allow you to write simpler and more concise code.
- Flexibility: Hooks can be used with both functional and class components.
- Reusability: Hooks are easy to reuse across different components.
- Performance: Hooks can improve the performance of your React applications.
Getting started with React hooks
To start using React hooks, you need to import the useState
hook from the react
library. This hook allows you to create and manage state in a functional component.
import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
In the example above, we are using the useState
hook to create a state variable called count
. We then use the setCount
function to update the state variable when the button is clicked.
Other React hooks
In addition to the useState
hook, there are a number of other React hooks that you can use. Some of the most popular hooks include:
useEffect
: This hook allows you to perform side effects in a functional component, such as fetching data or setting up subscriptions.useContext
: This hook allows you to access context data from a functional component.useReducer
: This hook allows you to manage complex state in a functional component.useCallback
: This hook allows you to memoize callback functions, which can improve the performance of your application.useMemo
: This hook allows you to memoize the result of a function, which can also improve the performance of your application.
Learning more about React hooks
There are a number of resources available to help you learn more about React hooks. The official React documentation is a good place to start. You can also find many helpful tutorials and articles online.
Conclusion
React hooks are a powerful tool that can help you write better React code. If you are a React developer, I encourage you to learn more about hooks and start using them in your projects.
Meta lite studios for
productions and virtual reality in New York City
and take action. My name is Murtadha.
I’m a software engineer at Meta based on
the Seattle office. React hooks were
first introduced at a React conference and
it was shared with the community and
the community of React enthusiast who are
excited about the new things and they’re the people
that we trust to give us the feedback and test out the things that
we’re thinking about. I had gone on vacation
and came back and my co-worker had been saying, there’s this new exciting thing, let’s start using it, and I looked at it and I
thought, this is so silly. Why do we need this
thing and he’s like, no trust me, this is
going to be great, so I was like, okay fine. I started learning them
and start using them. Now I can’t imagine writing
code without hooks. At first, it sometimes feels
a little unintuitive or there’s a lot of magic going on that doesn’t make
sense right away. But once you get the hang of it and you start using it and understanding it actually really makes life easier to use. Hooks can actually simplify your applications
greatly and introduce performance gains that can make your code more readable
and easier to manage, as well as your code more
shareable and reusable. Before the
introduction of hooks, we were using class components, and they seemed like they
were doing their job. But with time, this class components
were becoming bigger. They were becoming
quite complex. We couldn’t really break
certain components down into more modular
components or pieces. We wanted to make
code more usable. We wanted to make it simpler and remove this need for having these huge bloated
components that we’re not able to be broken
into smaller pieces. When we develop new
technologies at Meta, we tried to be the
first users of those things to make sure
they actually work and we get to be watching the feedback as it comes
directly from our engineers, so the same thing with hooks. We started actually using
them internally a lot. We saw that internal teams are also starting to
really appreciate the improvements that
hook introduced and so that really
justified that hooks are making a big difference
in the process of developing React applications and it gave rise to rolling it
out more widely. When hooks were introduced, they were actually introduced in a non-breaking wave which meant that you don’t have to use them. You could continue to use
the old style of writing React components and
they didn’t break anything that was
previously written. This is one of the
approaches that we use when we roll out new things that we want to make sure
this new thing doesn’t break any of the old
things that people are doing.. My advice for
you as you’re learning hooks and working with them for the first time is
to stick it out. They may seem hard and
confusing at first, but they actually will improve your code with time
and it may be tempting to use the old way of writing React code but
actually with hooks, you will find that
once you learn them, code will make more
sense with hooks. Even if at first seemed a
little confusing and intuitive. Take the time to learn them, make that investment upfront and you’ll find that it’s
worth it in the long run.
Video: Revising useState hook
This video teaches you how to use the useState hook to track state in a React app. You will learn how to use the useState hook to set initial state, update state, and respond to user events.
The useState hook returns an array with two values: the current state value and a function to update the state. You can use the state value to display data to the user and the update function to change the data when the user interacts with the app.
The video provides a practical example of using the useState hook to track the restaurant name in a React app. The example shows how to use the useState hook to set the initial value of the restaurant name to “Lemon” and then update it to “Little Lemon” when the user clicks a button.
The video also explains the concept of destructuring arrays. Destructuring arrays allows you to extract individual values from an array into separate variables. This can be useful for working with the state returned by the useState hook.
Overall, this video provides a good introduction to using the useState hook to track state in a React app. The video is clear and concise, and the practical example is helpful.
Revising useState hook in React
The useState hook is a React hook that allows you to manage state in your components. It is one of the most fundamental hooks in React, and it is used in almost every React component.
The useState hook takes a single argument, which is the initial value of the state variable. It returns an array with two values: the current value of the state variable and a function to update the state variable.
To use the useState hook, you first need to import it from the React library:
import React, { useState } from "react";
Then, you can use the useState hook in your component like this:
const MyComponent = () => {
const [count, setCount] = useState(0);
return (
<div>
<h1>Count: {count}</h1>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
};
In this example, we are using the useState hook to create a state variable called count
. The initial value of count
is 0. We are also creating a function called setCount
. This function will be used to update the value of the count
state variable.
When the user clicks the button, the setCount
function will be called and the value of count
will be incremented by 1. This will cause the count
state variable to be updated, and the count
element in the UI will be updated accordingly.
The useState hook is a powerful tool for managing state in React components. It is easy to use and it provides a simple way to update state in response to user events.
Here are some additional tips for using the useState hook:
- Use descriptive names for your state variables. This will make your code more readable and maintainable.
- Avoid using nested state variables. This can make your code more difficult to understand and debug.
- Use the useState hook to manage immutable state. This will help to prevent bugs and make your code more predictable.
- Use the useEffect hook to perform side effects after the state of your component has changed.
Overall, the useState hook is a powerful and versatile tool for managing state in React components. By following the tips above, you can use the useState hook to write efficient and maintainable React code.
Which of the following is true about the useState hook?
Select all that apply.
The useState hook’s return value in React is the array data structure.
That’s correct. The invocation of the useState hook returns an array.
The useState hook allows you to work with state in components.
That’s correct. The useState hook is used to work with state in a React component.
The useState hook invocation returns a two-member array.
That’s correct. When calling the useState() hook, the returned array holds the state variable’s value asthe first item of that array and the function that will be used to update the stateas the second item of that returned array.
When using the useState hook, you must use the state-updating function to update state.
That’s correct. There is only one correct way to update state when using useState and that’s through the state-updating function.
Imagine that Little Lemon needs a way to
track the restaurant’s food inventory in this video. You’ll work through some practical
examples using an app built for Little Lemon to revise
the used state hook and explore how the useState hook is invoked,
you’ll examine the return values of the useState hook and
how it’s used to update state. You are probably already familiar with
a used state hook which is used to work with state in a react component
with state being all the data and app is working with at a given time. But before moving on to use state, let’s
revisit the concept of a radi structuring, recall that a raid is structuring is
a way to get individual items from an array of items and save those
individual items as separate components. Now let’s explore this concept
with a practical example. Say you’re coding an app that tracks
current food reserves in Little Lemons pantry, you’re using a variable to
keep all the veggies in an array. As you continue to code, you realize you need to get each item from
the array into its own separate variable. For the first item in the array, you want to name the variable V1
as in veggie one, the second item. V2 and so on. With a radi structuring, you can do this
easily using a single line of code for more information on a radi structuring, you can refer to the additional
resources at the end of this lesson. Note that with a radi structuring,
you’re free to give any variable name to the items that you
D structure from an array. However, when the structuring objects,
you have to d structure a property of an object using that exact properties name
as the name of the d structured variable. This makes objects a lot stricter in
terms of what you can name your D structure variables. For that reason,
react uses the array data structure for the used state hooks return value. Now that you’ve had a sneak preview of
the return value of the useState hook. Let’s explore how it actually works. I will demonstrate how to update state and
react apps by using the use state hook to set the initial value of
the restaurant name to Lemon and then using only the use state updating
function to update it to little Lemon. The use state hook allows you to
work with state in components. Let’s start discussing state by
revising what happens when I called the youth state hook. I’m only returning null from here because
I want to focus on the console for now inspecting the console. This is what gets logged. The console logged value is an array with
the state variables value being the first item in the array. The second item in the returned
array is the function that will be used to update the state. So the use state hook invocation
returns a two member array. The convention is to name the state
updating function using camel case. Another convention is to name
it by pre pending the words set to the variable name used for
the D structured state variable. In other words, the correct way to work
with state means that by starting code example should be improved to correctly D. Structure the array returned from
the call to the useState hook. Now the D structured restaurant
name variable holds the state and the D structured set. Restaurant name variable holds
the state updating function. This is an example of a radi
structuring using the used state hook. You may be wondering how you can update
state Well when first starting to use the use state hook. Some developers try to update the state
variable in a variety of ways, but there is only one correct way to
update state when using use state and that’s through the state
updating function. In other words, the only way to update
the state of the restaurant name variable is by invoking the set restaurant name
function in a react app state changes are usually triggered through the act
of a user interacting with the app. This means that state changes are usually
triggered by user generated events. These events such as mouse movements,
button clicks and key presses happen all the time. In an app, the role of the developers to
respond to specific kinds of events in a way that’s meaningful to the app. That’s being coded. One common way users interact with
web apps is through button clicks. So let’s examine an example of changing
state in response to these user generated events, namely button clicks. In this example code I’m adding a button
which when clicked will execute a function. This function is update restaurant
name which is invoked wherever I user clicks on the button. Now when I click the update restaurant
name button that will change the H. One heading from Lemon to Little Lemon. Because the invocation of the update
restaurant named function triggered a call to the set restaurant name
state setting function. You should now be able to
recall what they used. State hook is used for and
how it works in practice. I hope that working with the useState
hook will be a fuss free task for you going forward especially when working
with primitive data types to track state in a component.
Reading: Working with complex data in useState
Reading
In this reading, you will learn how to use objects as state variables when using useState. You will also discover the proper way to only update specific properties, such as state objects and why this is done. This will be demonstrated by exploring what happens when changing the string data type to an object.
An example of holding state in an object and updating it based on user-generated events
When you need to hold state in an object and update it, initially, you might try something like this:
import { useState } from "react";
export default function App() {
const [greeting, setGreeting] = useState({ greet: "Hello, World" });
console.log(greeting, setGreeting);
function updateGreeting() {
setGreeting({ greet: "Hello, World-Wide Web" });
}
return (
<div>
<h1>{greeting.greet}</h1>
<button onClick={updateGreeting}>Update greeting</button>
</div>
);
}
While this works, it’s not the recommended way of working with state objects in React, this is because the state object usually has more than a single property, and it is costly to update the entire object just for the sake of updating only a small part of it.
The correct way to update the state object in React when using useState
The suggested approach for updating the state object in React when using useState is to copy the state object and then update the copy.
This usually involves using the spread operator (…).
Keeping this in mind, here’s the updated code:
import { useState } from "react";
export default function App() {
const [greeting, setGreeting] = useState({ greet: "Hello, World" });
console.log(greeting, setGreeting);
function updateGreeting() {
const newGreeting = {...greeting};
newGreeting.greet = "Hello, World-Wide Web";
setGreeting(newGreeting);
}
return (
<div>
<h1>{greeting.greet}</h1>
<button onClick={updateGreeting}>Update greeting</button>
</div>
);
}
Incorrect ways of trying to update the state object
To prove that a copy of the old state object is needed to update state, let’s explore what happens when you try to update the old state object directly:
import { useState } from "react";
export default function App() {
const [greeting, setGreeting] = useState({ greet: "Hello, World" });
console.log(greeting, setGreeting);
function updateGreeting() {
greeting = {greet: "Hello, World-Wide Web};
setGreeting(greeting);
}
return (
<div>
<h1>{greeting.greet}</h1>
<button onClick={updateGreeting}>Update greeting</button>
</div>
);
}
The above code does not work because it has a TypeError hiding inside of it.
Specifically, the TypeError is: “Assignment to constant variable”.
In other words, you cannot reassign a variable declared using const, such as in the case of the useState hook’s array destructuring:
const [greeting, setGreeting] = useState({ greet: "Hello, World" });
Another approach you might attempt to use to work around the suggested way of updating state when working with a state object might be the following:
import { useState } from "react";
export default function App() {
const [greeting, setGreeting] = useState({ greet: "Hello, World" });
console.log(greeting, setGreeting);
function updateGreeting() {
greeting.greet = "Hello, World-Wide Web;
setGreeting(greeting);
}
return (
<div>
<h1>{greeting.greet}</h1>
<button onClick={updateGreeting}>Update greeting</button>
</div>
);
}
The above code is problematic because it doesn’t throw any errors; however, it also doesn’t update the heading, so it is not working correctly. This means that, regardless of how many times you click the “Update greeting” button, it will still be “Hello, World”.
To reiterate, the proper way of working with state when it’s saved as an object is to:
- Copy the old state object using the spread (…) operator and save it into a new variable and
- Pass the new variable to the state-updating function
Updating the state object using arrow functions
Now, let’s use a more complex object to update state.
The state object now has two properties: greet and location.
The intention of this update is to demonstrate what to do when only a specific property of the state object is changing, while keeping the remaining properties unchanged:
import { useState } from "react";
export default function App() {
const [greeting, setGreeting] = useState(
{
greet: "Hello",
place: "World"
}
);
console.log(greeting, setGreeting);
function updateGreeting() {
setGreeting(prevState => {
return {...prevState, place: "World-Wide Web"}
});
}
return (
<div>
<h1>{greeting.greet}, {greeting.place}</h1>
<button onClick={updateGreeting}>Update greeting</button>
</div>
);
}
The reason this works is because it uses the previous state, which is named prevState, and this is the previous value of the greeting variable. In other words, it makes a copy of the prevState object, and updates only the place property on the copied object. It then returns a brand-new object:
return {...prevState, place: "World-Wide Web"}
Everything is wrapped in curly braces so that this new object is built correctly, and it is returned from the call to setGreeting.
Conclusion
You have learned what happens when changing the string data type to an object, with examples of holding state in an object and updating it based on user-generated events. You also learned about correct and incorrect ways to update the state object in React when using useState, and about updating the state object using arrow functions.
Video: Using the useState hook
This tutorial demonstrates how to build a goals app in React using the useState hook to declare, read, and update state.
The app consists of three components:
- Goal form: This component captures a new goal using a form.
- List of goals: This component loops over all the previously added goals and displays them as an unordered list of list items.
- App: This component puts the other two components together and allows the user to interact with them.
The goal form component uses the useState hook to declare a state variable called formData. This variable stores the goal and by values that the user enters into the form.
The submit handler function in the goal form component updates the allGoals state variable in the app component. This state variable stores a list of all the goals that the user has added.
The list of goals component uses the allGoals state variable to render a list of list items, each of which represents a goal.
The app component passes the addGoal function to the goal form component as a prop. This function allows the goal form component to add a new goal to the allGoals state variable.
To use the app, the user simply enters a goal and a timeframe into the form and clicks the submit button. The goal will then be added to the list of goals.
This tutorial provides a good overview of how to use the useState hook to declare, read, and update state in React.
Tutorial on using the useState hook in React
The useState hook is a React hook that allows you to manage state in your components. State is data that can change over time, and it is essential for building dynamic and interactive UIs.
To use the useState hook, you first need to declare a state variable. This can be done by calling the useState function and passing in the initial value of the state variable. For example:
const [count, setCount] = useState(0);
This declares a state variable called count
with an initial value of 0. The setCount
function is a callback function that is used to update the value of the count
state variable.
To update the state variable, you simply call the setCount
function with the new value of the state variable. For example:
setCount(count + 1);
This will increment the value of the count
state variable by 1.
You can then use the state variable in your component to render dynamic UI. For example:
return (
<div>
<h1>Count: {count}</h1>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
This will render a button that increments the count when clicked.
The useState hook is a powerful tool for managing state in React components. It is easy to use and provides a simple way to update state and render dynamic UI.
Here are some additional tips for using the useState hook:
- Use descriptive names for your state variables. This will make your code more readable and maintainable.
- Avoid mutating state directly. Instead, use the
setCount
function to update state. This will help to keep your code immutable and easier to reason about. - Use the useState hook to manage all of the state in your component. This will help to keep your code organized and maintainable.
By following these tips, you can use the useState hook to write efficient and effective React code.
You can use an object with multiple properties as the initial value of the state variable.
True
That’s correct! You can use an object with multiple properties as the initial value of the state variable, just like the formData state variable in the example, where the useState hook was invoked with the object containing two properties (the goal property and the by property).
Imagine it’s the very early
days of Little Lemon, with the restaurant
only existing on paper. The owner would like an app
to track the development of the restaurant business and the achievement of
all related goals. Let’s explore how to build a goals app with the
described requirements in react using the use state hook in a component and
updating the state. The completed app, is now displayed on screen. When this code is compiled, I get a heading that reads my. Little Lemon goals
and then I have a simple form with two
inputs, goal and by. The first input field
is there to let the owner type out
their goal and the second input field is
there to let them type out the timeframe within which they want to achieve a given goal. The code itself consists of
three separate components. Goal form, which captures
a new goal using a forum, list of goals, which loops over all the previously added
goals and displays them as an unordered list of list
items and the app component, which puts those two components together and allows
me to render them, as well as pass the
functions that they’ll be working with through
their props. Let’s explore these. The first component, namely the goal form component, accepts the prompts objects. In the body of the
goal form function, I start by declaring a state
variable of forum data, which is D structured from a
call to the use State hook. I initialize this form data variable as an object
with two properties, goal and by, both assigned the values
of empty strings. Next, I declare two functions, change handler and
submit handler. First is the change
handler function which accepts an E parameter. This E parameter is a readily
available event object. In other words, I don’t have to pass this object from
my change handler. It’s provided to me by a
mechanism outside of React. Even in plain JavaScript, whenever an event is fired, this creates an
event object with many different pieces of
data related to the event. I can then use this
event object by simply assigning it a
custom name such as E, EVT, or Even event. I’m using the letter E here
to keep my code concise. In the body of the
change handler function, I update the state of my form data variable
by invoking the previously D structured
state-setting variable of a set form data, which was D structured from a
call to the use State hook. The set form data
function accepts a shallow clone of the previous value of
the form data variable. That’s the form
data variable with the spread operator
before it here. Remember that you
should not work with the form data variable
directly which is why, I’m making a copy. This is because of how React
optimizes its virtual DOM. Keeping state immutable makes it possible to compare a
previous version of the virtual DOM with the updated version more efficiently and
cost effectively. Next, I update this new copy of the form data object
by adding this code, it reads the E target name
using the bracket notation. Then sets the value of this property to
whatever is inside that E.target.value property
of the instance of the event object, which was built when that
specific event was fired. The reason why this works with the brackets notation is that it allows me to set the value of the E target
named dynamically. In other words, it allows
me to set it as goal, If the user typed into
the input with the name attributes set to Goal
or to set it as By, If the user typed into the input with the name
attributes set to By. Second, I declare a
submit handler function which also accepts
the event attribute. The goal form component
receives the prop named on Add, and I’m giving the function add goal to it as the props value. But it’s not just any function. It’s actually a function
that’s declared right here on line 43 inside the
app component itself. This add goal function accepts a goal entry and
updates the value of add goals state variable that’s kept inside
the app function. It does this by adding this goal entry to the
list of previous goals saved and tracked inside the all goal state variable
of the app component. The update of any state
variable must go through the previously D structured
state updating function. In the case of the
app component, the state updating function is the update all goals function. That’s why I’m invoking the state updating function
inside the add goal function. To make it all work, I also need to pass the add
goal function definition to the goal forum JSX element in the app component’s
return statement. That’s why the add
goal function is now available as a prop
named on Add inside the goal form function
and that’s why I can now use it inside the
submit handler function, starting up here on Line 10. I’m back in the goal form
function declaration. Once the props dot on Add function is invoked
here on Line 12, it receives the
form data variable, which triggers the update
of the all goals state variable in the app component
as described previously. I still have the form showing the values that
the user entered. To deal with this,
I need to reset the form data state variable
to an empty string, both on the goal property of the form data state object and the buy property of the
form data state object. This now brings me to the return statement of
the goal form function. I want you to focus on the
form element that has the on submit event handling attribute set to the submit
handler function. The first and second
inputs both follow the same structure of
having the type, name, placeholder, value, and
on change attributes, which hawk into the previously
described functionality. Moving on to the list
of goals component, this component receives
the all goal state variable as a prop from
its parent app component. The purpose of this is to map over the all goals
array of objects where each object holds
the two properties that describe a single
goal as explained earlier. By mapping over the all
goals array of objects, I now output this
unordered list with a list item entry for
each individual goal. Having now worked through
coding a goals app in React, you should have
greater insight into using the use State hook
within a component, including how to declare, read, and update state.
Lab: Exercise: Managing state within a component
Reading: Solution: Managing state within a component
Reading
Here is the completed solution code for the App.js file:
import { useState } from "react";
export default function App() {
const [giftCard, setGiftCard] = useState(
{
firstName: "Jennifer",
lastName: "Smith",
text: "Free dinner for 4 guests",
valid: true,
instructions: "To use your coupon, click the button below.",
}
);
function spendGiftCard() {
setGiftCard(prevState => {
return {
...prevState,
text: "Your coupon has been used.",
valid: false,
instructions: "Please visit our restaurant to renew your gift card.",
}
});
}
return (
<div style={{padding: '40px'}}>
<h1>
Gift Card Page
</h1>
<h2>
Customer: {giftCard.firstName} {giftCard.lastName}
</h2>
<h3>
{giftCard.text}
</h3>
<p>
{giftCard.instructions}
</p>
{
giftCard.valid && (
<button onClick={spendGiftCard}>
Spend Gift Card
</button>
)
}
</div>
);
}
Here is the output from the solution code for the App.js file.
Step-by-step solution
Step 1
You opened the App.js file and located the spendGiftCard() function.
Inside the spendGiftCard() function, you invoked the setGiftCard() state-updating function, without passing it any parameters or doing anything else with it.
function spendGiftCard() {
setGiftCard()
}
Step 2
Inside the setGiftCard() function invocation’s parentheses, you passed in an arrow function.
This arrow function has a single parameter, named prevState. After the arrow, you added a block of code.
function spendGiftCard() {
setGiftCard(prevState => {
})
}
Step 3
Next, you returned a copy of the prevState objectusing the rest operator.
function spendGiftCard() {
setGiftCard(prevState => {
return ...prevState
})
}
Step 4
Next, you combined this copy of the prevState object with those properties that you wanted updated, by updating some of the key-value pairs that already exist on the state object that were initially passed to the useState() function call.
function spendGiftCard() {
setGiftCard(prevState => {
return {
...prevState,
text: "Your coupon has been used.",
}
})
}
Step 5
Finally, you updated the remaining properties on the state object.
You updated the valid key’s value to false.
Then, updated the instructions key’s value to Please visit our restaurant to renew your gift card.
function spendGiftCard() {
setGiftCard(prevState => {
return {
...prevState,
text: "Your coupon has been used.",
valid: false,
instructions: "Please visit our restaurant to renew your gift card.",
}
});
}
Practice Quiz: Self-review: Managing state within a component
Is this a valid useState hook invocation and destructuring? const [car, setCar] = useState({ color: ‘blue’, mileage: 0})
Yes
Correct. This code shows a valid call to the useState() hook. It’s also correctly destructured to car and setCar.
AI assistant
Yes, the useState hook invocation and destructuring in your example is valid.
The useState
hook takes two arguments: the initial state and a function to update the state. In your example, the initial state is an object with two properties: color
and mileage
. The function to update the state is called setCar
.
The destructuring in your example assigns the initial state to the variables car
and setCar
. This allows you to access the state values directly in your code.
Here is an example of how you could use the car
and setCar
variables:
const [car, setCar] = useState({ color: 'blue', mileage: 0 });
// Change the car's color.
setCar({ ...car, color: 'red' });
// Get the car's mileage.
const mileage = car.mileage;
By using the useState
hook and destructuring, you can easily manage state in your React applications.
True or False: You can clone a JS object using the . operator (the dot operator).
False
Correct. The dot operator is not used to clone an object in JS.
AI assistant
False. You cannot clone a JS object using the . operator (the dot operator). The . operator is used to access properties of objects, not to clone them.
To clone a JS object, you can use the following methods:
- Object.assign(): The
Object.assign()
method copies the properties of one object to another object. - JSON.parse() and JSON.stringify(): The
JSON.parse()
andJSON.stringify()
methods can be used to serialize and deserialize objects, respectively. This can be used to create a copy of an object. - Deep copy libraries: There are a number of third-party libraries that can be used to create deep copies of objects.
Here is an example of how to clone a JS object using the Object.assign()
method:
const originalObject = {
name: 'John Doe',
age: 30,
};
const clonedObject = Object.assign({}, originalObject);
// clonedObject is now a copy of originalObject.
By using one of the methods above, you can clone a JS object and avoid accidentally modifying the original object.
Consider the following code: u003cbru003econst [person, setPerson] = useState({ name: ‘John’, age: 21}) u003cbru003eImagine you’re using a setPerson() state-updating function to update the value of the state variable named person. You only want to update the value of age, from 21 to 22. Choose the correct code snippet to do that.
setPerson(prev => ({ ...prev, age: 22 }));
Yes, this snippet is correct, because it clones the previous state object, and updates only the cloned object’s age value.
AI assistant
The correct code snippet to update the value of the age
property of the person
state variable from 21 to 22 is:
setPerson({ ...person, age: 22 });
The ...person
operator copies all of the properties of the person
object to the new object. This ensures that the other properties of the person
object are not overwritten.
The following code snippet is also valid, but it is not as efficient as the first code snippet:
setPerson({ age: 22 });
This code snippet creates a new object with only the age
property set to 22. This object is then passed to the setPerson()
function.
While this code snippet is valid, it is less efficient because it creates a new object for each time the age
property is updated. The first code snippet is more efficient because it only copies the person
object once.
By using the ...person
operator, you can avoid creating unnecessary objects and improve the performance of your code.
Video: What are side effects?
This video discusses side effects in React components, including pure and impure functions, and how the useEffect hook is used to perform side effects within functional components.
A side effect is something that makes a function impure. Pure functions don’t have side effects, and impure functions do.
A pure function should always return the same output for the same input. An impure function may change state outside of itself, or make external calls.
The useEffect hook is used to perform side effects within functional components. It takes two parameters: a callback function and an array of dependencies. The callback function is executed after the component mounts and when any of the dependencies change.
The video provides an example of a shopping cart function that is impure because it logs the total amount to the console. The video then shows how to use the useEffect hook to make the shopping cart function pure.
In general, it is best to avoid impure functions in React components. If you need to perform a side effect, you should use the useEffect hook to isolate the side effect from the rest of the component.
Side effects in React
A side effect is something that happens outside of a function. This can include things like:
- Changing state outside of the function
- Making external calls, such as to an API or database
- Logging to the console
- Changing the DOM
Side effects can make your code more difficult to reason about and test. They can also make it more difficult to optimize your code for performance.
In React, it is generally best to avoid side effects in your functional components. This is because functional components are supposed to be pure functions. A pure function is a function that always returns the same output for the same input.
If you need to perform a side effect in your React component, you should use the useEffect
hook. The useEffect
hook allows you to perform side effects after the component mounts and when any of the dependencies change.
Here is an example of a function that uses the useEffect
hook to perform a side effect:
function MyComponent() {
const [count, setCount] = useState(0);
useEffect(() => {
// This function will be executed after the component mounts and whenever the count state changes.
fetch('/api/users')
.then(response => response.json())
.then(users => {
setCount(users.length);
});
}, [count]);
return (
<div>
<h1>The count is: {count}</h1>
</div>
);
}
The useEffect
hook takes two parameters:
- A callback function: This function will be executed after the component mounts and whenever any of the dependencies change.
- An array of dependencies: This array contains the values that the callback function depends on. If any of these values change, the callback function will be executed again.
In this example, the callback function makes an API call to get a list of users. The callback function depends on the count
state. If the count
state changes, the callback function will be executed again to fetch the latest list of users.
It is important to note that the useEffect
hook should be used sparingly. If you find yourself using the useEffect
hook in many places in your component, it is a sign that your component is probably too complex. You should try to break down your component into smaller, simpler components that can be more easily tested and optimized.
True or False:
A pure function will perform a side effect.
False
That’s correct. While a pure function has no side effects, an impure function will perform a side effect.
Before moving on to using another hook. Known as the use Effect hook,
let’s take some time to consider its name. The name of the use Effect hook is closely
related to the concept of an effect or more precisely a side effect. In this video you will learn what side
effects within a react component are, including what pure and
impure functions are. And their relation to side effects as well
as how use Effect is used to perform side effects within functional components. So what is a side effect? A side effect is something
that makes a function in pure. Did you know that functions
can be classified as pure and impure simply put pure functions
don’t have side effects. And impure functions do let’s
unpack the concept of pure and impure functions in relation
to side effects and more. A pure function should
receive specific input. That is a specific parameter will
always return the exact same output. No matter how many times it gets invoked. To illustrate let’s explore a function
that uses the year little lemon was established. In this example the established year
component accepts a props object that is a props parameter. It also returns a value that is
a heading that outputs the words established year followed
by a colon space. And the value of the year prop as long
as the value of the year prop is 2003. Regardless of how many times the
established year function is invoked or it is rendered from the app component,
the output will remain unchanged. This is an example of a pure function. The established year function
has no side effects. By contrast and impure function
will perform a side effect. That means it will do things such as
invoke console log, invoke, fetch or invoke browsers geolocation functionality. In this context, a side effect can be
thought of as something external to or outside of a function. Consider the example of a ShoppingCart
function built for the little lemon app. It is an impure function because of
the line that reads console log total. The console log call makes the function
impure as it’s a call to a browser, application programming interface or API. The ShoppingCart function now depends
on something outside of itself and even outside of the react
app to work properly. So how should you deal with the issue
of impure functions in react. Well, it’s all about containing the impure
actions inside their own special areas. To do this and
react you need to use the use Effect hook, let’s update the ShoppingCart component
with the use Effect hook to properly deal with the side effect
caused by the console log. First, you need to import
the use Effect hook from react the use Effect hook works by
accepting two parameters. The first is a callback function. The second parameter is an array. This array can be kept empty which is
perfectly valid while the syntax is valid. It’s common to use an arrow function as
the first argument of the invocation of the use Effect hook. Note that the use Effect has been
simplified to a single line of code. It usually spends several lines of code
that’s because it typically needs to do something more meaningful than
just console logging the value of the components variable. In this video, you learned about pure and
impure functions and their relation to side effects. Exploring with side effects
within a react component are, and briefly how use Effect
is used to perform them. You can look forward to applying this
knowledge by using the use Effect hook introduced in this video
to perform side effects.
Reading: What is the useEffect hook?
Reading
You have been introduced to the primary usage of the useEffect hook, a built-in React hook best suited to perform side effects in your React components.
In this reading you will be introduced to the correct usage of the dependency array and the different useEffect calls that can be used to separate different concerns. You will also learn how you can clean up resources and free up memory in your useEffect logic by returning a function.
The code you place inside the useEffect hook always runs after your component mounts or, in other words, after React has updated the DOM.
In addition, depending on your configuration via the dependencies array, your effects can also run when certain state variables or props change.
By default, if no second argument is provided to the useEffect function, the effect will run after every render.
useEffect(() => {
document.title = 'Little Lemon';
});
However, that may cause performance issues, especially if your side effects are computationally intensive. A way to instruct React to skip applying an effect is passing an array as a second parameter to useEffect.
In the below example, the integer variable version is passed as the second parameter. That means that the effect will only be re-run if the version number changes between renders.
useEffect(() => {
document.title = `Little Lemon, v${version}`;
}, [version]); // Only re-run the effect if version changes
If version is 2 and the component re-renders and version still equals 2, React will compare [2] from the previous render and [2] from the next render. Since all items inside the array are the same, React would skip running the effect.
Use multiple Effects to Separate Concerns
React doesn’t limit you in the number of effects your component can have. In fact, it encourages you to group related logic together in the same effect and break up unrelated logic into different effects.
function MenuPage(props) {
const [data, setData] = useState([]);
useEffect(() => {
document.title = 'Little Lemon';
}, []);
useEffect(() => {
fetch(`https://littlelemon/menu/${id}`)
.then(response => response.json())
.then(json => setData(json));
}, [props.id]);
// ...
}
Multiple hooks allow you to split the code based on what it is doing, improving code readability and modularity.
Effects with Cleanup
Some side effects may need to clean up resources or memory that is not required anymore, avoiding any memory leaks that could slow down your applications.
For example, you may want to set up a subscription to an external data source. In that scenario, it is vital to perform a cleanup after the effect finishes its execution.
How can you achieve that? In line with the previous point of splitting the code based on what it is doing, the useEffect hook has been designed to keep the code for adding and removing a subscription together, since it’s tightly related.
If your effect returns a function, React will run it when it’s time to clean up resources and free unused memory.
function LittleLemonChat(props) {
const [status, chatStatus] = useState('offline');
useEffect(() => {
LemonChat.subscribeToMessages(props.chatId, () => setStatus('online'))
return () => {
setStatus('offline');
LemonChat.unsubscribeFromMessages(props.chatId);
};
}, []);
// ...
}
Returning a function is optional and it’s the mechanism React provides in case you need to perform additional cleanup in your components.
React will make sure to run the cleanup logic when it’s needed. The execution will always happen when the component unmounts. However, in effects that run after every render and not just once, React will also clean up the effect from the previous render before running the new effect next time.
Conclusion
In this lesson, you learned some practical tips for using the built-in Effect hook. In particular, you were presented with how to use the dependency array properly, how to separate different concerns in different effects, and finally how to clean up unused resources by returning an optional function inside the effect.
Video: Using the useEffect hook
The useEffect hook is used to perform side effects in React. Side effects are actions that can affect the state of the component outside of React, such as updating the DOM, making HTTP requests, or setting timers.
How to use the useEffect hook:
To use the useEffect hook, you pass it a function that contains the side effect code. This function will be executed after the component has rendered.
Controlling when the useEffect function is run:
You can control when the useEffect function is run by passing it a dependency array. The dependency array is a list of variables that the useEffect hook will watch for changes. If any of the variables in the dependency array change, the useEffect function will be re-executed.
Example:
The following code shows how to use the useEffect hook to update the title of the browser tab:
import React, { useState, useEffect } from 'react';
function App() {
const [toggle, setToggle] = useState(false);
useEffect(() => {
document.title = toggle ? 'Welcome to Little Lemon' : 'Using the useEffect Hook';
}, [toggle]);
return (
<div>
<h1>Little Lemon</h1>
<button onClick={() => setToggle(!toggle)}>Toggle message</button>
</div>
);
}
export default App;
In this example, the useEffect hook will be executed every time the value of the toggle
variable changes. This will cause the title of the browser tab to be updated accordingly.
Empty dependency array:
If you pass an empty dependency array to the useEffect hook, it will only be executed once, after the component has mounted.
Conclusion:
The useEffect hook is a powerful tool for performing side effects in React. By understanding how to use the useEffect hook and the dependency array, you can control when side effects are executed and ensure that your React applications are efficient and performant.
Tutorial: Using the useEffect Hook in React
The useEffect hook is a React hook that allows you to perform side effects in your components. Side effects are actions that can affect the state of the component outside of React, such as updating the DOM, making HTTP requests, or setting timers.
The useEffect hook is typically used to perform the following tasks:
- Update the DOM
- Make HTTP requests
- Set timers
- Listen for events
- Clean up resources
To use the useEffect hook, you pass it a function that contains the side effect code. This function will be executed after the component has rendered.
You can also pass a second argument to the useEffect hook, which is a dependency array. The dependency array is a list of variables that the useEffect hook will watch for changes. If any of the variables in the dependency array change, the useEffect function will be re-executed.
Example:
The following code shows a simple example of how to use the useEffect hook to update the DOM:
import React, { useState, useEffect } from 'react';
function App() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `Count: ${count}`;
}, [count]);
return (
<div>
<h1>Count: {count}</h1>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
export default App;
In this example, the useEffect hook will be executed every time the value of the count
variable changes. This will cause the title of the browser tab to be updated accordingly.
Empty dependency array:
If you pass an empty dependency array to the useEffect hook, it will only be executed once, after the component has mounted.
This can be useful for performing side effects that only need to be done once, such as setting up an event listener or initializing a timer.
Cleaning up resources:
The useEffect hook can also be used to clean up resources when a component unmounts. To do this, you can return a function from the useEffect hook that will be executed when the component unmounts.
This can be useful for cleaning up resources such as event listeners, timers, and open connections.
Example:
The following code shows how to use the useEffect hook to clean up an event listener:
import React, { useState, useEffect } from 'react';
function App() {
const [count, setCount] = useState(0);
useEffect(() => {
const handleClick = () => {
setCount(count + 1);
};
document.addEventListener('click', handleClick);
return () => {
document.removeEventListener('click', handleClick);
};
}, []);
return (
<div>
<h1>Count: {count}</h1>
</div>
);
}
export default App;
In this example, the handleClick
function is added as an event listener to the document
object. When the component unmounts, the useEffect
hook will return a function that removes the event listener.
This ensures that the event listener is always cleaned up, even if the component unmounts prematurely.
Conclusion:
The useEffect hook is a powerful tool for performing side effects in React. By understanding how to use the useEffect hook, you can write more efficient and performant React applications.
How should you add a side effect functionality In React?
Using the useEffect hook
That’s correct. The correct way to add a side effect functionality is to use the useEffect function.
To demonstrate how to use the useEffect hook
within a component, let’s continue working
on the Little Lemon app. Say the owner of the
restaurant wants to add a specific way for the user
to interact with the app. On a button click, the owner wants a welcome
message displayed, and on another button click, the owner wants the
message hidden. Additionally, the owner
wants this change to be reflected on the Browser tab
where the app is served. Updating a Browser tab is an
example of a side effect. In this video, I will demonstrate
how to do this by using the useEffect hook to perform
side effects in React, as well as how to control when the useEffect function is run using the
dependencies array. I’m going to use an app
I built previously using Create React App to demonstrate how to use
the useEffect hook. To describe what’s happening, let’s start with a
return statement. I have a wrapping div
and inside of it, an h1, a button in a JSX
expression that uses the logical and operator to
conditionally render an h2. The button has an onClick
event handling attribute and it triggers the
clickHandler function, which I’ve declared as a function expression
starting on line 7. On line 5, I’ve destructured the
toggle variable from a call to the useState
hook to track the state of the toggle
variable and make the conditional rendering in the return statement possible. Now, let’s inspect my app in the browser as it’s
currently being served. Everything is working well. When I click the
button, the sentence, welcome to Little Lemon
appears under it if it wasn’t shown previously,
and vice versa. Although the app
is working well, my app currently has no way of updating the text
in the Browser tab, like the restaurant
owner wants it to do. This is an example
of a side effect, which is why the
correct way to add this functionality is to
use the useEffect hook. Above the return statement, I’ll add a call to the useEffect function as
follows, React.useEffect. I need to pass a function
to the useEffect call. I’ll add an arrow function
without parameters, and in the body of
the arrow function, I’ll add this ternary here, which checks if the value of the toggle variable
is true or false. If it’s true, it should
return the string that reads, welcome to Little Lemon. Otherwise, it should
return the string that reads using the useEffect hook. Whatever gets returned
is the value I’m assigning to the title property
of the document object. This property thus
dynamically updates the text showing them the tab of the browser where this
React app is served. Let’s inspect the updated
app in the browser. I can confirm that with
every click of the button, the title on the
tab is updating to one of the two
specified strings. Imagine that the owner has
changed his mind and he wants the title on the document to be set on the initial
component render. After that, it doesn’t
want it updated. This is where the
dependency array comes in. The dependency array determines when the useEffect
hook will be invoked. For now, I’ll update my code with an empty
dependency array, meaning I’m not tracking the state of any
state variables. In other words, regardless of what is happening in my app, I don’t want the useEffect
hook to be invoked. This means that it’ll
be invoked only once. After that, no matter
what happens in my app, the useEffect hook
will no longer be run. Now that I’ve updated my app, let’s save the changes
and examine how this affects the behavior of
my app in the browser. The useEffect hook
runs only once, outputs the words using
the useEffect hook. After that, regardless of how many times I click on
the Toggle message button, there are no further
updates to the tab title. The dependency array is there to watch for changes to
a specific variable. Based on that, execute the
function that’s passed in as the first argument of
the useEffect function call. This means that if I want
to run the useEffect hook whenever there’s an update to the value stored in
the toggle variable, I need to add the
toggle variable to the dependencies array. After this change, back in the browser, the useEffect hook
will be run every time the Toggle message
button is clicked. Because the clickHandler
updates the value of the toggle state variable by invoking the setToggle function. This in turn, triggers
the useEffect invocation. Since the dependencies
array is set to watch for changes to the
toggle variables value. There you go. I have a
way to fulfill any of the restaurant owners
requests that might involve some side effects
in my React apps. You should now have
a better idea of how to use the useEffect
function to handle side effects and of how to use the dependency array to determine when it
will be invoked.
Practice Quiz: Knowledge check: Getting started with hooks
Imagine you have to log into the console a state variable, whenever the variable gets updated. What’s the best place to perform such operation in a React component?
the useEffect hook
Correct! All side effects should be inside the useEffect hook.
AI assistant
The best place to log a state variable to the console whenever it gets updated is in the useEffect
hook, before the return statement of the component.
The useEffect
hook allows you to perform side effects in your React components. Side effects are actions that can affect the state of the component outside of React, such as updating the DOM, making HTTP requests, or logging to the console.
To log a state variable to the console in the useEffect
hook, you can use the following code:
JavaScript
import React, { useState, useEffect } from 'react';
function App() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log(count);
}, [count]);
return (
<div>
<h1>Count: {count}</h1>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
export default App;
In this example, the useEffect
hook will be executed every time the value of the count
variable changes. This will cause the value of the count
variable to be logged to the console.
Logging state variables to the console can be useful for debugging and understanding how your React components are working.
Here is an example of how to use the useEffect
hook to log a state variable to the console before the return statement of the component:
import React, { useState, useEffect } from 'react';
function App() {
const [count, setCount] = useState(0);
// Log the count variable to the console before the return statement
useEffect(() => {
console.log(count);
}, [count]);
return (
<div>
<h1>Count: {count}</h1>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
export default App;
When you run this code, you will see the following output in the console:
0
1
2
3
...
The useEffect hook accepts… 1 point a callback function and an array two callback functions a callback function and an object
a callback function and an array
That’s correct! The useEffect hook accepts a callback function and an array.
AI assistant
The useEffect hook accepts a callback function and an array as arguments.
The callback function is the code that will be executed after the component has rendered.
The array is a list of variables that the useEffect hook will watch for changes. If any of the variables in the dependency array change, the useEffect function will be re-executed.
If you pass an empty dependency array to the useEffect hook, it will only be executed once, after the component has mounted.
Example:
import React, { useState, useEffect } from 'react';
function App() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log(count);
}, [count]);
return (
<div>
<h1>Count: {count}</h1>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
export default App;
In this example, the useEffect function will be executed every time the value of the count
variable changes. This will cause the value of the count
variable to be logged to the console.
The useEffect hook is a powerful tool for performing side effects in React. By understanding how to use the useEffect hook, you can write more efficient and performant React applications.
What is a pure React component?
A component that doesn’t have any side effects
AI assistant
A pure React component is a component that does not have any side effects. This means that it does not change any state outside of its own component scope, and it does not perform any actions that affect the outside world, such as making HTTP requests or updating the DOM.
Pure components are easier to reason about and test, and they can also improve the performance of your React applications.
Examples of pure React components:
- A component that renders a list of items
- A component that renders a form
- A component that renders a button
Examples of impure React components:
- A component that makes an HTTP request to fetch data
- A component that updates the DOM in response to user input
- A component that uses a timer
Benefits of using pure React components:
- Easier to reason about and test
- Can improve the performance of your React applications
How to make a React component pure:
To make a React component pure, you should:
- Avoid using state outside of the component’s own scope.
- Avoid performing actions that affect the outside world, such as making HTTP requests or updating the DOM.
If you need to perform an action that affects the outside world, you can use the useEffect
hook.
Conclusion:
Pure React components are a valuable tool for writing efficient and performant React applications. By understanding what pure components are and how to use them, you can write better code and improve the performance of your apps.
What is the name of the second argument of the useEffect() call?
the dependency array
Correct! The name of the second argument is the dependency array.
AI assistant
The second argument of the useEffect() call is called the dependency array. It is an optional array of values that React will compare to the previous render’s values. If any of the values in the dependency array have changed, React will re-run the effect.
The dependency array is useful for preventing unnecessary renders. For example, if you have an effect that fetches data from an API, you can add the data to the dependency array. This will ensure that the effect is only re-run when the data has changed.
Here is an example of how to use the dependency array:
import { useEffect } from "react";
function MyComponent() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log("Effect ran");
}, [count]); // The dependency array
return (
<div>
<h1>Count: {count}</h1>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
In this example, the effect will only re-run when the count
state variable changes. This is because the count
variable is added to the dependency array.
If you omit the dependency array, the effect will be re-run on every render. This can be useful in some cases, but it can also lead to performance problems.
This code is incomplete:u003cbru003eReact.useEffect(()=u003e {u003cbru003econsole.log(‘The value of the toggle variable is’,toggle)u003cbru003e}, [])u003cbru003eYou need to update the dependecies array so that the useEffect hook is invoked whenever the toggle variable updates. Choose the correct solution from the choices below.
The dependencies array should receive the toggle variable as its single member.
Correct. The dependencies array should receive the toggle variable as its single member: [toggle].
AI assistant
The correct solution is to update the dependencies array to: [{toggle}].
The dependencies array tells React which variables the effect depends on. If any of the variables in the dependencies array change, React will re-run the effect.
In this case, the effect depends on the toggle
variable. So, we need to add the toggle
variable to the dependencies array.
Here is the updated code:
React.useEffect(() => {
console.log('The value of the toggle variable is', toggle)
}, [toggle])
Now, the effect will re-run whenever the toggle
variable changes.
The other options are incorrect:
- The dependencies array should not be removed. If we remove the dependencies array, the effect will re-run on every render. This can lead to performance problems.
- The dependencies array should not be replaced with
{toggle}
. This is not a valid JavaScript syntax.
I hope this helps!
Reading: Additional resources
Reading
Below is a list of additional resources as you continue to explore React hooks and custom hooks.
In particular, to complement your learning in the “Getting started with hooks” lesson, you can work through the following:
- The article on destructuring assignment describes how the destructuring assignment, which allows you to get values out of the array that gets returned when the useState hook is invoked, works in more detail.
- The read props inside the child component link on the Beta version of React docs discusses how to use destructuring assignment to get values out of the props object.
- The useState reference on official React docs website helps you understand how to work with this hook and some of the caveats involved.
- The useEffect reference on official React docs website helps you understand the syntax of this hook and goes into some depth to explain how to use and troubleshoot the useEffect hook.
Rules of Hooks and Fetching Data with Hooks
Video: What are the rules of hooks?
Four rules of hooks in React
- Only call hooks from React component functions. Do not call hooks from regular JavaScript functions.
- Only call hooks at the top level of a React component function. Do not call hooks inside loops, conditions, or nested functions.
- You can call multiple state hooks or effect hooks inside a component.
- Always call multiple hooks in the same sequence.
Why follow these rules?
Following these rules ensures that React can correctly track the state and effects of your components. It also helps to prevent errors and unexpected behavior.
Examples
Here are some examples of valid and invalid hook usage:
// Valid
function MyComponent() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log(`Count: ${count}`);
}, [count]);
return <button onClick={() => setCount(count + 1)}>Increment</button>;
}
// Invalid
function MyComponent() {
if (count > 0) {
useEffect(() => {
console.log(`Count: ${count}`);
}, [count]);
}
return <button onClick={() => setCount(count + 1)}>Increment</button>;
}
In the second example, the useEffect hook is called conditionally. This is invalid because it can cause the hook to be skipped when compared with the previous render.
Tips for using hooks correctly
- Always call hooks at the top level of your component functions.
- If you need to call a hook conditionally, place the condition inside the hook.
- Be careful not to call hooks from regular JavaScript functions or from inside loops, conditions, or nested functions.
By following these tips, you can use hooks effectively and write clean and maintainable React code.
What are the rules of hooks in React?
Hooks are a new feature in React that allow you to use state and other React features without writing classes. However, there are a few rules that you need to follow when using hooks.
Rule 1: Only call hooks from React component functions.
You cannot call hooks from regular JavaScript functions. Instead, you can only call hooks from React component functions. This is because hooks need to be able to track the state of your components and cause re-renders when necessary.
Rule 2: Only call hooks at the top level of a React component function.
You cannot call hooks inside loops, conditions, or nested functions. This is because hooks need to be called in the same order each time the component renders. If you call hooks inside loops, conditions, or nested functions, the order in which they are called could change, which could lead to errors.
Rule 3: You can call multiple state hooks or effect hooks inside a component.
You are allowed to call multiple state hooks or effect hooks inside a component. However, you should always call them in the same order each time the component renders.
Rule 4: Always call multiple hooks in the same sequence.
If you call multiple hooks in a component, you should always call them in the same sequence each time the component renders. This is because hooks rely on the order in which they are called to work correctly. If you change the order in which you call hooks, it could lead to errors.
Why are the rules of hooks important?
The rules of hooks are important because they help to ensure that hooks work correctly and that your React code is clean and maintainable. If you break the rules of hooks, you may encounter errors or unexpected behavior.
How to follow the rules of hooks
To follow the rules of hooks, simply keep the following in mind:
- Only call hooks from React component functions.
- Only call hooks at the top level of a React component function.
- You can call multiple state hooks or effect hooks inside a component.
- Always call multiple hooks in the same sequence.
If you are unsure whether or not a particular piece of code follows the rules of hooks, you can use the ESLint plugin eslint-plugin-react-hooks
to check your code for errors.
Example
Here is an example of a React component that follows the rules of hooks:
JavaScript
function MyComponent() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log(`Count: ${count}`);
}, [count]);
return <button onClick={() => setCount(count + 1)}>Increment</button>;
}
In this example, the useState
and useEffect
hooks are both called at the top level of the component function. They are also called in the same order each time the component renders.
Conclusion
Following the rules of hooks is important for writing clean and maintainable React code. By following the rules of hooks, you can avoid errors and ensure that your hooks work correctly.
Is this code using a valid invocation of a hook?
if (data !== '') {
useEffect( () => {
setData('test data')
})
}
No
That’s correct. The useEffect hook has been used inside the If conditional statement, and that makes the use of the hook in this code invalid.
By now, you should have a fairly
good idea about the purpose and functionality of hooks in React. And you may have even started using
hooks in some of your solutions. If so, you may have encountered some
cases where hooks might have made your code invalid. Well, that’s because there are a few basic
rules to hooks that you need to be aware of and follow in your React apps. In this video, you will learn all
about the rules of hooks in React and why they are so important, and why you
would only call hooks at the top level and from React functions. The four main rules of
hooks are as follows. First, you should only call hooks
from a React component function. Second, you should only call hooks at the
top level of a React component function. Third, you are allowed to
call multiple state hooks or effect hooks inside a component. And finally, always make these multiple
hook calls in the same sequence. Now, let’s unpack each of these
rules in a little more detail. The first rule means that you should
not be calling hooks from regular Javascript functions, instead you should only call them from
inside a React component function. From a built-in hook call, for
example, from the useEffect hook or from a custom hook. In this example, the code describes a button that can be
clicked to pick up a new name for a pet. The nameLooper function is used to limit
the pet name choices to only fluffy, rexy, or gizmo. Notice that the useState hook is
accessed at the outermost scope of the app function, it has not been
used anywhere other than this. For example,
inside the nameLooper function scope. However, you may have observed that
this rule does not prevent you from using the state setting function
which is named setPetName here. State setting calls can be
used wherever required. The second rule means you must call your
hooks before a return statement outside of loops, conditions or nested functions. If you use a hook in a condition,
you’re breaking rules. For example, here, the useEffect
hook has been used inside the if conditional statement, that makes the use
of the hook in this code invalid. The third rule is straightforward. There can be multiple hook calls as long
as they are always in the same order. What that means is that you cannot place
hook calls inside conditional because that might result in an invocation of a hook
being skipped when compared with the previous render. In this example, with the same code that
describes a button that can be clicked to pick up a new name for a pet, the useState
hook has been used incorrectly. Rather than using the state setting
function said petName inside the nameLooper function, the useState
hook has been used here instead. If you were to compile the code and
run the app, you may find that the expected
output is returned. For example, I’d like to name my pet fluffy with a pick
a new name button rendered beneath. However, as soon as you click
the pick a new name button, you would receive an invalid
hook called error. That would violate the fourth rule. In other words, it might disrupt the sequence of
invocation from one render to the next. Such a violation would result in errors. If you want to call an effect
conditionally you can still do so, but make sure to place
the condition inside the hook. Here, the useEffect hook is invoked
initially followed by the if conditional statement. So now, you’re not breaking the rules and
the code is valid. So let’s recap on the four
main rules of hooks. You should only call hooks from
a React component function. You should only call hooks at the top
level of a React component function. You are allowed to call multiple state
hooks or effect hooks inside a component. And finally, always make these multiple
hook calls in the same sequence, and that’s it. In this video, you learn the main
rules of using hooks in React and why you would only call hooks at the top
level of and from React functions. As long as you stick to
these few simple rules, you can enjoy using hooks in your
React solutions successfully.
Video: What you need to know before fetching data
The Fetch function in JavaScript is a powerful tool for retrieving data from the web, but it is important to understand how it works before using it. JavaScript is single-threaded, meaning that it can only do one thing at a time. To get around this limitation, JavaScript uses a technique called asynchronous programming. This means that JavaScript can delegate tasks to other parts of the browser, such as the Fetch API, and continue executing other code while those tasks are being completed.
The Fetch function is a facade function, meaning that it is a function that looks like it is part of JavaScript, but it actually calls a browser API. The Fetch API is a browser API that is external and separate from JavaScript. It is responsible for making requests to servers and retrieving data.
To use the Fetch function, you first need to create a new fetch object. This object can be used to configure the request, such as the URL to fetch and the method to use (GET, POST, PUT, etc.). Once you have created the fetch object, you can call the fetch() method to start the request.
The fetch() method is asynchronous, meaning that it will return a promise. A promise is an object that represents the eventual completion or failure of an asynchronous operation. The promise returned by the fetch() method will resolve to a Response object when the request is complete.
The Response object contains information about the response, such as the status code and headers. You can use the Response object to get the body of the response, which is the data that was retrieved from the server.
Here is an example of how to use the Fetch function to retrieve data from a JSON API:
const fetch = require('fetch');
const url = 'https://randomuser.me/api/';
const response = await fetch(url);
const data = await response.json();
console.log(data);
This code will fetch the data from the JSON API and log it to the console.
The Fetch function is a powerful tool for retrieving data from the web, but it is important to understand how it works before using it. By understanding how asynchronous programming works in JavaScript, you can write code that is more efficient and responsive.
What you need to know before fetching data in React
Fetching data is a common task in React applications. We often need to fetch data from a server to display it in our components. However, there are a few things you need to know before fetching data in React.
1. Understand how asynchronous programming works in JavaScript
JavaScript is a single-threaded language, which means that it can only do one thing at a time. This can be a problem when fetching data, because we don’t want our application to freeze while we wait for the data to be retrieved.
To get around this, JavaScript uses a technique called asynchronous programming. Asynchronous programming allows us to start a task and then continue executing other code while the task is being completed.
When we fetch data in React, we are using asynchronous programming. This means that we need to be prepared to handle the results of the fetch operation asynchronously.
2. Choose the right data fetching library
There are a number of different data fetching libraries available for React. Some of the most popular libraries include:
- Axios
- Fetch
- Relay
- Apollo Client
Each of these libraries has its own strengths and weaknesses. It is important to choose the library that is right for your needs.
3. Consider using a state management library
State management libraries can help you to manage the state of your React application. This can be especially helpful when fetching data, because you need to keep track of the loading state of the data, the errors that may occur, and the data itself.
Some of the most popular state management libraries include:
- Redux
- MobX
- Recoil
4. Use a consistent fetching strategy
It is important to use a consistent fetching strategy throughout your React application. This will help to make your code more maintainable and predictable.
One common fetching strategy is to use the following steps:
- Create a component that is responsible for fetching the data.
- Use the
useState
hook to track the loading state of the data and the errors that may occur. - Use the
useEffect
hook to fetch the data when the component mounts. - Display the data in the component once it has been fetched.
5. Handle errors gracefully
It is important to handle errors gracefully when fetching data. This means that you should have a plan for what to do if the fetch operation fails.
One common approach is to display an error message to the user. You may also want to log the error to the console so that you can track it down and fix it.
Conclusion
Fetching data is a common task in React applications. By following the tips above, you can ensure that your code is efficient, maintainable, and predictable.
Which of the below statements is an accurate description of JavaScript utilizing the fetch function?
When JavaScript uses the fetch function it is delegating duties to an external API so that it can continue its process. This is known as asynchronous JavaScript.
That’s correct. The fetch function utilizes external APIs to perform tasks that would be cumbersome for JavaScript to fulfil alone.
The Fetch function is
a very useful tool, but there are some important
things that you need to understand before you
start using them. Initially, it’s good to get an overview of how
JavaScript delegates duties so that you
can gain insight into how the Fetch function
contributes to this process. In this video, you
will learn how the Fetch function works
to retrieve data from the web and how to provide an example in plain
JavaScript of the process. Fetch is used to make
a server requests to retrieve some
JSON data from it. Fetch API is a set of
functionalities that we have at our disposal to use in JavaScript to make
such a server request. It’s a bit like a clerk
at the post office. Say you’re bringing a package to the post office and you’re
the first in the queue. The clerk on the other side of the service desk is JavaScript. Since they can only do
one thing at a time. They go through the process
of getting your details, measuring the weight
of the package, pasting stamps onto the package, charging you for the service, and go into the back-office and carrying the package there, then taking time to find the correct place for the
package before it gets shipped. The problem with this
approach is that the next step cannot start before the previous
one is finished. That’s what’s known as
single-threaded execution. Since JavaScript is not at
all equipped to multitask, a way to go around this
issue is as follows. First, JavaScript
gets your details. At the same time, it calls a clerk to measure
the weight of the package. Then JavaScript calls yet another clerk to paste some
stamps onto the package. Javascript calls
yet another clerk to charge you for the service, and yet another clerk is called to carry the package
to the back-office, allowing JavaScript to take
care of the next customer. Essentially, this delegation
of duties is what’s referred to as
asynchronous JavaScript. In this metaphor,
you can think of the browser as the post office, Javascript as one clerk
in the post office and all these other clerks
can be referred to as browser APIs or web APIs. Now let’s explore a
practical example of how this delegation of
duties works in JavaScript. I have a local HTML file. The most important part of
this file is the script tag, which is getting some JavaScript
code from the file named script.js located in the same
folder as this HTML file. I’m serving these
files locally using the live server VS
Code extension. Let me inspect this HTML
file in the browser. Currently it only shows H_1 heading that
reads fetching data. Now, let me take a step back and let’s say the JavaScript, the post office worker, needs to get some user data
from the computer database. Here is the JavaScript
code inside the link to script.js file. What do you expect the output
of this code will be since JavaScript can only do one single thing
at any given time. Well, let’s explore what the
code is doing step-by-step. On Line 1, it performs a console log for the words
another customer approaching. Then it contacts the Fetch API, which is a browser API that is external and separate
from JavaScript. Rather than waiting for the Fetch API to return
the information, it keeps on executing the
code that comes after it, outputting the texts that
begins our valued customer. In the meantime, the Fetch API requests some user data
from a third party web-based API available at the random user dot.me Website. The fetch function is what’s
known as a facade function. Meaning it’s a function that looks like it’s
part of JavaScript, but actually it is
just a way for me to call a browser API
from JavaScript. In other words, it’s a way
for me to access a piece of browser functionality
that’s outside of JavaScript. You can think of it as the
JavaScript post office clerk calling the records
department of the post office to get some
data about a customer. When the other clerk
gets back with the information and hands it over to the
post office clerk, then they will get a
JSON representation, and finally, we’ll log
that data to the console. That means that the sequence of console logs from the
code will be as follows. An initial console
log that outputs another customer approaching
a second console log that outputs our valued
customer please wait a moment while I get
some information back from the
records department, and a final console log
that outputs the data. I will now execute this code to confirm that
describe the behavior. Everything is already saved. All I need to have this code executed is to go
back to the browser, right-click on the
page and press the reload command to refresh it. You can achieve
the same result by pressing the F5 key
on your keyboard. Now, I first get
another customer approaching then the
our valued customer. Finally, the result of the
call to the third party API. This is how JavaScript, although being single-threaded, can perform asynchronous
operations. In this video, you learned how the Fetch function works
to retrieve data from the web and how to provide an example in plain
JavaScript of the process. You should be familiar
with this concept before fetching data in React, which I’ll explore soon.
Reading: Data fetching using hooks
Reading
You learned more about fetching data using hooks and that fetching data from a third-party API is considered a side-effect that requires the use of the useEffect hook to deal with the Fetch API calls in React.
You also explored how the response from fetching third-party data might fail, or be delayed, and that it can be useful to provide different renders, based on whether or not the data has been received.
In this reading, you will explore the different approaches to setting up the useEffect hook when fetching JSON data from the web. You will also learn why it can be useful to provide different renders, based on whether or not the data has been received.
You have previously learned about using the Fetch API to get some JSON data from a third-party website in plain JavaScript.
You’ll be glad to learn that data fetching is not that different in React.
There is only one more ingredient that you need to keep in mind when working with React, namely, that fetching data from a third-party API is considered a side-effect.
Being a side-effect, you need to use the useEffect hook to deal with using the Fetch API calls in React.
To understand what that entails, let me illustrate it with a code example where a component is fetching some data from an external API to display information about a cryptocurrency.
import { useState, useEffect } from "react";
export default function App() {
const [btcData, setBtcData] = useState({});
useEffect(() => {
fetch(`https://api.coindesk.com/v1/bpi/currentprice.json`)
.then((response) => response.json())
.then((jsonData) => setBtcData(jsonData.bpi.USD))
.catch((error) => console.log(error));
}, []);
return (
<>
<h1>Current BTC/USD data</h1>
<p>Code: {btcData.code}</p>
<p>Symbol: {btcData.symbol}</p>
<p>Rate: {btcData.rate}</p>
<p>Description: {btcData.description}</p>
<p>Rate Float: {btcData.rate_float}</p>
</>
);
}
This example shows that in order to fetch data from a third party API, you need to pass an anonymous function as a call to the useEffect hook.
useEffect(
() => {
// ... data fetching code goes here
},
[]
);
The code above emphasizes the fact that the useEffect hook takes two arguments, and that the first argument holds the anonymous function, which, inside its body, holds the data fetching code.
Alternatively, you might extract this anonymous function into a separate function expression or function declaration, and then just reference it.
Using the above example, that code could be presented as follows:
import { useState, useEffect } from "react";
export default function App() {
const [btcData, setBtcData] = useState({});
const fetchData = () => {
fetch(`https://api.coindesk.com/v1/bpi/currentprice.json`)
.then((response) => response.json())
.then((jsonData) => setBtcData(jsonData.bpi.USD))
.catch((error) => console.log(error));
};
useEffect(() => {
fetchData();
}, []);
return (
<>
<h1>Current BTC/USD data</h1>
<p>Code: {btcData.code}</p>
<p>Symbol: {btcData.symbol}</p>
<p>Rate: {btcData.rate}</p>
<p>Description: {btcData.description}</p>
<p>Rate Float: {btcData.rate_float}</p>
</>
);
}
The code essentially does the same thing, but this second example is cleaner and better organized.
One additional thing that can be discussed here is the return statement of the above example.
Very often, the response from fetching third-party data might fail, or be delayed. That’s why it can be useful to provide different renders, based on whether or not the data has been received.
The simplest conditional rendering might involve setting up two renders, based on whether or not the data has been successfully fetched.
For example:
return someStateVariable.length > 0 ? (
<div>
<h1>Data returned:</h1>
<h2>{someStateVariable.results[0].price}</h2>
</div>
) : (
<h1>Data pending...</h1>
);
In this example, I’m conditionally returning an h1 and h2, if the length of the someStateVariable binding’s length is longer than 0.
This approach would work if the someStateVariable holds an array.
If the someStateVariable is initialized as an empty array, passed to the call to the useState hook, then it would be possible to update this state variable with an array item that might get returned from a fetch() call to a third-party JSON data provider.
If this works out as described above, the length of the someStateVariable would increase from the starting length of zero – because an empty array’s length is zero.
Let’s inspect the conditional return again:
return someStateVariable.length > 0 ? (
<div>
<h1>Data returned:</h1>
<h2>{someStateVariable.results[0].price}</h2>
</div>
) : (
<h1>Data pending...</h1>
);
If the data fetching fails, the text of “Data pending…” will render on the screen, since the length of the someStateVariable will remain being zero.
Conclusion
You learned more about fetching data using hooks and that fetching data from a third-party API is considered a side-effect that requires the use of the useEffect hook to deal with the Fetch API calls in React.
You also explored how the response from fetching third-party data might fail, or be delayed, and that it can be useful to provide different renders, based on whether or not the data has been received.
Video: Fetching data – Putting it all together
The Little Lemon restaurant wants to run a competition for its customers where a lucky customer will receive a free meal. To do this, they will need to get some random user data from a website. In this video, the author shows how to do this using the random.me website and the React framework.
The author has prepared some code to fetch the user data from the website. The code first outputs a “data pending” message in the H1 heading. In the background, it is carrying out a function to retrieve the user information from the random user website.
Once the data has been successfully fetched, the code updates the view with the data returned in the H1 heading and the user information that has been retrieved. In this example, the data that was requested was the first name and the last name of the random user.
The author then steps through the code in more detail. They explain that they are using the useState hook to manage the state of the component. The useState hook allows them to store and update data that is specific to the component.
The author also explains that they are using the useEffect hook to fetch the data from the random user website. The useEffect hook allows them to perform side effects in their React components, such as fetching data or setting up subscriptions.
The author then explains how they are using conditional logic to decide what to return. If the state array is empty, the code returns a “data pending” message. Otherwise, the code returns a div section with the H1 tag and a couple of H2 tags.
Finally, the author explains how the Little Lemon restaurant could apply the same logic to their customer list API to select a random winner for their competition.
Overall, this video provides a good overview of how to fetch data from the web using React.
Fetching data – Putting it all together in React
Overview:
In React, we can use the useState and useEffect hooks to fetch data from an API and then display it in our component. The useState hook allows us to store and update data that is specific to the component, while the useEffect hook allows us to perform side effects in our React components, such as fetching data or setting up subscriptions.
Steps:
- Import the useState and useEffect hooks from React.
- Declare a state variable to store the fetched data.
- Create a fetch data function that uses the fetch() API to fetch data from the API.
- Use the useEffect hook to call the fetch data function when the component mounts.
- Use conditional logic to render the fetched data in the component.
Example:
import { useState, useEffect } from "react";
const MyComponent = () => {
const [data, setData] = useState([]);
const fetchData = async () => {
const response = await fetch("https://api.example.com/data");
const data = await response.json();
setData(data);
};
useEffect(() => {
fetchData();
}, []);
if (data.length === 0) {
return <p>Loading data...</p>;
} else {
return (
<ul>
{data.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
);
}
};
export default MyComponent;
In this example, we use the useState hook to store the fetched data in the data
state variable. We then use the useEffect hook to call the fetchData
function when the component mounts. The fetchData
function uses the fetch() API to fetch data from the API and then stores the data in the data
state variable.
Finally, we use conditional logic to render the fetched data in the component. If the data
state variable is empty, we render a “Loading data…” message. Otherwise, we render a list of the fetched items.
Tips:
- Use the useEffect hook to fetch data when the component mounts or when a dependency changes.
- Use conditional logic to render the fetched data in the component.
- Handle errors gracefully.
- Use a loading spinner or other indicator to let the user know that the data is being fetched.
- Use caching to improve performance.
Conclusion:
Fetching data from an API is a common task in React applications. By using the useState and useEffect hooks, we can easily fetch data and display it in our components.
Which of the statements below best describes how the fetchData function is working?
The fetchData function is initially fetching data from the randomuser.me API, next it retrieves a response from the API in JSON format, and finally updates the state variable with the returned data.
That’s correct. The fetchData function initially fetches data from the randomuser.me API, next it retrieves a response from the API in JSON format, and finally updates the state variable with the returned data.
The little lemon restaurant wants to run a competition for its customers where
lucky customer will receive a free
meal at a restaurant. All customers that
are signed up to the little lemon
app will be entered into the competition and a random customer will be
selected as the winner. In this video, I will
show you how to get some random user
data from a website. I will be using the
random.me website to access random user data
for this demonstration. I have prepared some
code for this app to fetch the user data
from the website. If I execute this code, it will initially
output the data pending texts in the H1 heading. At the same time
in the background, it will be carrying out
the fetch data function to retrieve the user information from the random user website. Notice that I have the dev tools open and the Network tab active. I will click on the North
router link dropdown to artificially slow
down my connection. In the dropdown, I will
choose the slow 3G preset. This is so that I can observe
the data pending text in the heading before the data
gets fetched from the web. Once the data has been
successfully fetched, it updates the view with
the data returned H1 heading and the user information
that has been retrieved. In this example,
the data that was requested was the first name and the last name of
this random user. Let’s step through this
code in more detail. So first, I have the app
function and inside of it, following the rules of hook, I’m invoking the use state hook at the top level
of the component. The initial value of the state variable is an empty array. Next, I have defined the
fetch data function, which is fetching data from
the random user.name API, then it retrieves
the response from the API in JSON format. It then updates the state
variable with this JSON data. You may notice that I’m
not using a hook inside the fetch data function because that’s against the
rules of hooks. After that, I’m calling the use effect hook and from inside
they use effect hook, I’m calling the
fetch data function which I’ve defined previously. Finally, I’m using
conditional logic to decide what to return. First, I’m using the
object.keys code snippet to put all the keys of the
user object into an array. Since object.keys
returns an array, I can access the length
property on this array and check if the length of this array is greater than zero. If it is, it means
that the contents of the state array has changed
because as you may remember, the state variables
array was empty. So if the array is
no longer empty, then the div section
will be returned with the H1 tag and a
couple of H2 tags. Otherwise, the H1 tag below is returned that
reads data pending. Sometimes it can take a
little bit of time for the fetch data function to
retrieve the data requested. Therefore, the data
pending message will be displayed initially after
the code is executed. Once the data has arrived
from the fetch data call, this change in state causes
a re-render of my component. So the return statements
ternary operator is re-evaluated and that returns all the data from my
call to the fetch API. This is essentially how you get data from the web using React. So the a little lemon
restaurant would be able to apply
the same logic to their customer list API to select a random winner
for their competition. In this video, you have
learned how to fetch data using the state
and effect hook.
Lab: Exercise: Can you fetch data?
Reading
Task
You’ve learned how to fetch data in React.
In this code lab, you’ll practice fetching some data from the randomuser.me website’s API.
This code lab’s app, once completed, is supposed to show a single customer’s data for the Little Lemon Restaurant.
The starter code shows only an h1 heading, with the following text: “Data pending…”
Your task is to complete the data fetching using the fetch() function and to handle the returned Promise object using the then() methods.
In the return statement of the App component, you also need to add an h2 heading showing the customer’s name and the customer’s image from the data fetched from the random user API.
Here’s an example screenshot of the completed app served in the browser.
In other words, the completed app should display the following:
- An h1 heading with the text that reads “Customer data”.
- An h2 heading with the text that reads, for example: “Name: Liam”.
- An image tag showing an image returned from the fetched data.
Note: Before you begin, make sure you understand how to work with the Coursera Code Lab for the Advanced React course.
Steps
Step 1
Open the App.js file.
The App.js starting code is as follows:
import React from "react";
function App() {
const [user, setUser] = React.useState([]);
const fetchData = () => {
};
React.useEffect(() => {
fetchData();
}, []);
return Object.keys(user).length > 0 ? (
<div>
<h1>Customer data</h1>
</div>
) : (
<h1>Data pending...</h1>
);
}
export default App;
Locate the fetchData() function.
const fetchData = () => {
};
Inside the fetchData() function’s code block, execute the fetch() function, passing it a single string argument: “https://randomuser.me/api/?results=1”.
Step 2
Still inside the fetchData() function, under the fetch() function call, add the following piece of code:
.then((response) => response.json())
Step 3
Continuing from the previous step, add another then() call, which takes an arrow function.
The passed-in arrow function should receive a data argument and using that data argument, it should invoke the setUser() function, with the data passed to it.
Step 4
In the return statement of the App component, the starting code is as follows:
return Object.keys(user).length > 0 ? (
<div style={{padding: "40px"}}>
<h1>Customer data</h1>
</div>
) : (
<h1>Data pending...</h1>
);
Under the h1 heading, you need to add one line of code:
- an h2 heading, with the following code inside: Name:{user.results[0].name.first}
Step 5
In Step 4, you updated the return statement of the App component.
In this step, you need to add another line of code under the newly-added h2.
You need to add an img element, with the src attribute holding the following code:
- {user.results[0].picture.large}
Additionally, you need to add an alt attribute, as follows:
alt=""
Remember to self-close the img tag.
Conclusion
Save the changes and run the app.
Verify that the completed app, behaves as follows:
- It shows a heading that reads: “Customer data”.
- It shows a subheading, that shows a user name. For example, “Name: Ann”.
- It shows an image of that user under the name.
Reading: Solution: Can you fetch data?
Reading
Here is the completed solution code for the App.js file:
import React from "react";
function App() {
const [user, setUser] = React.useState([]);
const fetchData = () => {
fetch("https://randomuser.me/api/?results=1")
.then((response) => response.json())
.then((data) => setUser(data));
};
React.useEffect(() => {
fetchData();
}, []);
return Object.keys(user).length > 0 ? (
<div style={{padding: "40px"}}>
<h1>Customer data</h1>
<h2>Name: {user.results[0].name.first}</h2>
<img src={user.results[0].picture.large} alt="" />
</div>
) : (
<h1>Data pending...</h1>
);
}
export default App;
Here is the sample output from the solution code for the App.js file. Note that the lab produces a different random image and name with each refresh, so your output is likely to have a different name and a different customer image than the one shown below.
Important note
If your browser doesn’t automatically reload with the updates, please remember to manually refresh your browser to view the changes after modifying App.js.
Step-by-step solution
Step 1
Inside the fetchData() function’s code block, you executed the fetch() function, passing it a single string argument: “https://randomuser.me/api/?results=1”.
const fetchData = () => {
fetch("https://randomuser.me/api/?results=1")
};
Step 2
Next, inside the fetchData() function, under the fetch() function call, you added the following piece of code:
const fetchData = () => {
fetch("https://randomuser.me/api/?results=1")
.then((response) => response.json())
};
Step 3
You then added another then() call, which takes an arrow function.
The passed-in arrow function, receives a data argument, and using that data argument, it invokes the setUser() function, with the data passed to it.
const fetchData = () => {
fetch("https://randomuser.me/api/?results=1")
.then((response) => response.json())
.then((data) => setUser(data));
};
Step 4
In the return statement of the App component, under the h1 heading that reads “Customer data”, you added an h2 heading, with the following code: Name: {user.results[0].name.first}
return Object.keys(user).length > 0 ? (
<div style={{padding: "40px"}}>
<h1>Customer data</h1>
<h2>Name: {user.results[0].name.first}</h2>
</div>
) : (
<h1>Data pending...</h1>
);
Step 5
You then updated the return statement of the App component by adding another line of code under the newly-added h2.
You added an img element, with the src attribute and an alt attribute holding the following code: {user.results[0].picture.large}
return Object.keys(user).length > 0 ? (
<div style={{padding: "40px"}}>
<h1>Customer data</h1>
<h2>Name: {user.results[0].name.first}</h2>
<img src={user.results[0].picture.large}alt="" />
</div>
) : (
<h1>Data pending...</h1>
);
Practice Quiz: Self-review: Can you fetch data?
True or False: When invoking the fetch() function to get some JSON data from an API, you should pass it a URL.
True
Correct! When invoking the fetch() function to get some JSON data from an API, you should pass it a URL.
AI assistant
True. When invoking the fetch()
function to retrieve JSON data from an API, you should pass it a URL that points to the API endpoint from which you want to fetch the data. The URL specifies the location of the resource you want to access, and the fetch()
function makes an HTTP request to that URL to obtain the data.
True or False: After invoking the fetch() function, you need to add a call to the then() function.
True
Yes, it is correct that you need to add a call to the then() function after invoking the then() function.
AI assistant
True. After invoking the fetch()
function to make an HTTP request, you typically need to add a call to the .then()
function to handle the response from the server. The .then()
function allows you to work with the response data, which is often in the form of a promise, and perform actions such as parsing JSON or handling errors. It’s a fundamental part of using the fetch()
API in JavaScript to manage the asynchronous nature of web requests.
Choose the right way to handle the response from a fetch call.
then( response => response.json())
Correct. This is the right way to handle the response from a fetch call.
AI assistant
The correct way to handle the response from a fetch call is:
then(response => response.json())
This code uses the .json()
method to parse the response data as JSON, which is a common operation when dealing with API responses in JavaScript. It allows you to work with the data returned by the API in a structured format.
Video: APIs
To design a stable and bug-free API, it is important to:
- Involve multiple engineers in the design process. This helps to ensure that the API is well-thought-out and meets the needs of all stakeholders.
- Use type safety. This helps to prevent errors by ensuring that the data returned by the API matches the data that the client is expecting.
- Design the API for the future. This means thinking about how the API will evolve over time and making sure that it is flexible enough to accommodate changes.
- Keep it simple. Avoid overcomplicating the design of the API, as this can make it more difficult to use and maintain.
Here are some additional tips for designing a stable and bug-free API:
- Use a consistent style guide. This will help to ensure that the API is easy to understand and use.
- Document the API thoroughly. This includes providing clear and concise documentation for each endpoint, as well as examples of how to use the API.
- Test the API thoroughly. This includes unit testing, integration testing, and user acceptance testing.
- Monitor the API in production. This will help to identify any bugs or performance issues early on.
By following these tips, you can design a stable and bug-free API that will meet the needs of your users and help you to build successful applications.
Tutorial on APIs in React
APIs (Application Programming Interfaces) are a way for different software components to communicate with each other. They are used in a wide variety of applications, including React.
To use APIs in React, you can use the fetch()
API or a third-party library like Axios. The fetch()
API is a built-in JavaScript API that allows you to make HTTP requests. Axios is a popular third-party library that makes it easier to use the fetch()
API and provides additional features.
To make an API call in React, you can use the following steps:
- Import the
fetch
API or Axios. - Define the endpoint URL that you want to call.
- Make the API call using
fetch()
or Axios. - Handle the response from the API.
Here is an example of how to make an API call in React using the fetch()
API:
import React, { useState, useEffect } from 'react';
const MyComponent = () => {
const [users, setUsers] = useState([]);
useEffect(() => {
fetch('https://api.example.com/users')
.then(response => response.json())
.then(data => setUsers(data))
.catch(error => console.error(error));
}, []);
return (
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
};
export default MyComponent;
This code will make an API call to the https://api.example.com/users
endpoint and then set the users
state variable to the data that is returned from the API. The useEffect()
hook is used to ensure that the API call is only made once, when the component is first mounted.
Once you have made the API call, you can use the data that is returned in your React component. In the example above, the users
state variable is used to render a list of users.
Here are some additional tips for using APIs in React:
- Use a consistent naming convention for your API endpoints. This will make it easier to read and maintain your code.
- Document your APIs thoroughly. This includes providing clear and concise documentation for each endpoint, as well as examples of how to use the API.
- Use error handling to handle any errors that may occur when making API calls.
- Use caching to reduce the number of API calls that you need to make.
By following these tips, you can use APIs effectively in your React applications.
Imagine opening up
the landing page of Facebook or Instagram and all you see is just
emptiness because the things that fills
the data in there, the photos and the words and
the likes and the comments, all of those things are
coming through the API. Writing APIs with integrity, with efficiency is
an important part of the application development
process and without it, you basically don’t
have an application. My name is Murtadha. I’m a
software engineer at Meta, working in the Seattle office. The design process at Meta for APIs usually involves
multiple iterations, just in the same way
that when we write code, we get our peers and
colleagues to review it. We do the same with API. Somebody or a group of people would usually write
a document that’s a proposal for how the API would be and
what the structure is, what the agreements that each part of the application
will make with each other. Then that proposal is
usually placed forward. Other engineers will review
it, they’ll leave comments. They’ll say, this make sense, this needs to be changed,
this is not good. Then we iterate, we improve it. Then when the API
is looking good, it’s in the final stage we
then take it to the next step, which is building it. The building process,
the same thing happens. We’re going to
review the code that is implementing the design that was created and there are comments and feedback
and iterations. Once that’s complete, then
we have our API ready. Usually the process
of developing an API involves engineers on all
ends of the spectrum. We would be talking to the
front-end engineers and the back-end engineers
and people working in the middle layer in-between as well to make sure
that the APIs are consistent and make sense
across the entire stack. Basically, if you think about
APIs to just simplify it, it’s a way to talk
to different things. If you have your mobile phone, you have your application that you’re holding
in your hand, it has to talk to the server. The way it talks to the
server is through an API. If you want to
talk to something, you have to establish
some understanding. That understanding
is established between the developers
in order for it to be built into the
application and reflected in the way that
the API is designed. There are few things
we look for and follow when we’re
designing APIs. One of them is
ensuring type safety. Type safety is basically
a way to ensure that when you’re fetching
something from the back-end, you’re going to get
what you’re expecting. If you’re requesting a photo that you actually
do get a photo, not a video or something else. That’s an important
part of designing API to make sure
things don’t break. A lot of the
application failures happen when there’s a
mismatch in the data. Where you fetch
something you expect a certain object and
you get something else. That type safety
ensures these mistakes or problems are minimized and it increases the stability of
an application when you have that consistent type
safety across the stack. One of the things that I usually struggle with when designing API is making it such that
it will work for the future. There’s a little
bit of a sweet spot to aim for with this
that we can obsess about wanting to make
our APIs very compatible with the future and trying to anticipate how the
application will evolve, and we’re going to
need this and that, and let’s make it right away. But also sometimes that
could be too much. Finding that balance where
you think about the future, but not so much such that you’re holding yourself back from actually getting the work done. It’s just like with
everything in life, you try to anticipate, but also you try
to also focus on the problem in front
of you now and how you can address it effectively. I know APIs can be a little
overwhelming at times, so I’m wishing you
the best of luck. Take your time to learn them and don’t let that overwhelm
you or intimidate you. It’s okay that when
you’re looking at APIs you’re going to be
venturing into the back-end. Just know that you are taking on more scope and
more complexity and that’s going to be good
for you because you will become more attractive
to employers, you will expand your knowledge. Don’t let that intimidate
you or hold you back. It’s going to be
helpful to learn these skills and concepts. The advice that I want to give myself and everybody
who’s thinking about APIs is to keep it simple. Sometimes we tend
to overthink too and try to cram so
many things into APIs and try to make
it very fancy and very using complicated and
complex design patterns. But actually simplicity,
it is really important in API design and the readability
of it is a big plus. Keep it simple and try to keep it stable
and free of bugs.
Practice Quiz: Knowledge check: Rules of Hooks and Fetching Data with Hooks
True or false: You should not call hooks inside loops.
True
Correct! You should not call hooks inside loops.
AI assistant
True.
This is one of the fundamental rules of using React Hooks. Hooks should only be called at the top level of a function component, before any early returns. This is because React needs to be able to track the order in which Hooks are called in order to preserve their state between renders.
Calling Hooks inside loops or other conditional statements can lead to unexpected behavior and bugs. For example, if you call a useState
Hook inside a loop, React will not be able to track which state value belongs to which iteration of the loop. This can lead to errors when you try to use the state value outside of the loop.
To avoid calling Hooks inside loops, you can use a function or a memo hook to extract the logic that needs to call the Hook. For example, the following code shows how to extract the logic for calling a useState
Hook into a function:
const useCounter = () => {
const [count, setCount] = useState(0);
const increment = () => {
setCount(count + 1);
};
return { count, increment };
};
const MyComponent = () => {
const { count, increment } = useCounter();
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
);
};
In this example, the useCounter
function is used to extract the logic for calling the useState
Hook. This allows us to call the increment
function from inside the loop without having to worry about React not being able to track the state value.
By following the rule of not calling Hooks inside loops, you can write more robust and predictable React applications.
True or false: You should call hooks inside if statements.
False
Correct! You should not call hooks inside if statements.
AI assistant
False.
You should not call hooks inside if statements. This is because React needs to be able to track the order in which Hooks are called in order to preserve their state between renders.
Calling Hooks inside if statements can break this rule and lead to unexpected behavior and bugs. For example, if you call a useState
Hook inside an if statement, React may not be able to track which state value belongs to which branch of the if statement. This can lead to errors when you try to use the state value outside of the if statement.
To avoid calling Hooks inside if statements, you can use a function or a memo hook to extract the logic that needs to call the Hook. For example, the following code shows how to extract the logic for calling a useState
Hook into a function:
const useIsLoggedIn = () => {
const [isLoggedIn, setIsLoggedIn] = useState(false);
const login = () => {
setIsLoggedIn(true);
};
const logout = () => {
setIsLoggedIn(false);
};
return { isLoggedIn, login, logout };
};
const MyComponent = () => {
const { isLoggedIn, login, logout } = useIsLoggedIn();
if (isLoggedIn) {
return <div>You are logged in.</div>;
} else {
return <div>You are not logged in.</div>;
}
};
In this example, the useIsLoggedIn
function is used to extract the logic for calling the useState
Hook. This allows us to call the login
or logout
function from inside the if statement without having to worry about React not being able to track the state value.
By following the rule of not calling Hooks inside if statements, you can write more robust and predictable React applications.
True or false: You should call hooks inside nested functions.
False
Correct! You should not call hooks inside nested functions.
AI assistant
False. You should not call hooks inside nested functions.
This is because React needs to be able to track the order in which Hooks are called in order to preserve their state between renders. When you call a hook inside a nested function, React may not be able to track the order in which it was called, which can lead to unexpected behavior and bugs.
If you need to use a hook inside a nested function, you can extract the logic that needs to call the hook into a separate function and then call that function from inside the nested function. For example, the following code shows how to extract the logic for calling a useState
hook into a separate function:
const useCounter = () => {
const [count, setCount] = useState(0);
return { count, increment };
};
const MyComponent = () => {
const { count, increment } = useCounter();
const nestedFunction = () => {
// Call the `increment` function from inside the nested function.
increment();
};
return (
<div>
<p>Count: {count}</p>
<button onClick={nestedFunction}>Increment</button>
</div>
);
};
In this example, the useCounter
function is used to extract the logic for calling the useState
hook. This allows us to call the increment
function from inside the nested function without having to worry about React not being able to track the state value.
By following the rule of not calling hooks inside nested functions, you can write more robust and predictable React applications.
You are allowed to: 1 point only call a single effect hook inside a component. call multiple state hooks and effect hooks inside a component only call a single state hook inside a component
call multiple state hooks and effect hooks inside a component
That’s right! You can call multiple state hooks and effect hooks inside a component.
AI assistant
You are allowed to call multiple state hooks and effect hooks inside a component.
In fact, it is very common to call multiple state hooks inside a component. For example, the following code shows a component that uses two state hooks to track the count and the name of the user:
const MyComponent = () => {
const [count, setCount] = useState(0);
const [name, setName] = useState('John Doe');
return (
<div>
<p>Count: {count}</p>
<p>Name: {name}</p>
</div>
);
};
It is also common to call multiple effect hooks inside a component. For example, the following code shows a component that uses an effect hook to log the count to the console every time it changes:
JavaScript
const MyComponent = () => {
const [count, setCount] = useState(0);
useEffect(() => {
console.log(`Count: ${count}`);
}, [count]);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
};
There is no limit to the number of state hooks and effect hooks that you can call inside a component. However, it is important to keep in mind that each hook that you call adds some overhead to the component. Therefore, it is important to only call the hooks that you need and to optimize your code whenever possible.
Here are some tips for optimizing your code when using state hooks and effect hooks:
- Only call the hooks that you need.
- Use memo hooks to cache the results of expensive computations.
- Use debounce and throttle hooks to avoid making too many API calls or updating the DOM too often.
- Use batch updates to update the DOM in bulk.
By following these tips, you can write more efficient and performant React applications.
True or false: You don’t have to always make multiple hook calls in the same sequence.
False
Correct. If you’re making multiple hook calls, you always need to call them in the same sequence. You do have to always make multiple hook calls in the same sequence.
AI assistant
False. You should always make multiple hook calls in the same sequence. This is because React relies on the order in which hooks are called to preserve their state between renders.
If you change the order in which you call hooks, React may not be able to track the state of the hooks correctly. This can lead to unexpected behavior and bugs.
For example, the following code shows a component that calls two hooks in different orders on different renders:
const MyComponent = () => {
const [count, setCount] = useState(0);
const [name, setName] = useState('John Doe');
if (count === 0) {
setName('Jane Doe');
}
return (
<div>
<p>Count: {count}</p>
<p>Name: {name}</p>
</div>
);
};
On the first render, React will call the useState
hook for name
before the useState
hook for count
. On the second render, React will call the useState
hook for count
before the useState
hook for name
.
Because React is relying on the order in which hooks are called to preserve their state, this can lead to unexpected behavior. For example, if you try to use the name
state variable inside the if
statement, React may not be able to find the state variable because it was called in a different order on the previous render.
To avoid this problem, you should always make multiple hook calls in the same sequence. This will ensure that React can track the state of the hooks correctly and that your component will behave as expected.
How to fix the code example
To fix the code example above, you can move the if
statement outside of the useState
hooks. This will ensure that the hooks are always called in the same order, regardless of the value of the count
state variable:
JavaScript
const MyComponent = () => {
const [count, setCount] = useState(0);
const [name, setName] = useState('John Doe');
if (count === 0) {
setName('Jane Doe');
}
return (
<div>
<p>Count: {count}</p>
<p>Name: {name}</p>
</div>
);
};
This is just one example of how to avoid changing the order in which hooks are called. By following the rules for using hooks, you can write more robust and predictable React applications.
Reading: Additional resources
Reading
Below is a list of additional resources as you continue to explore React hooks and custom hooks.
In particular, to complement your learning on the ‘Rules of hooks and fetching data with hooks’ lesson, you can work through the following:
- The Rules of Hooks reading on Reactjs.org website gives you an overview of how to work with the hooks as recommended by the React Core team at Meta.
- The Fetching data with Effects article on React docs discusses fetching data using a few different approaches, including using async / await syntax.
- How to use promises is a resource that describes the “behind-the-scenes” of how data fetching works in greater depth.
- async function is a resource on MDN that discusses the use of the async and await keywords as a more recent way to handle API requests in JavaScript.
Advanced hooks
Video: What is useReducer and how it differs from useState
The useReducer hook is a powerful alternative to the useState hook for managing complex state logic. It takes a reducer function and an initial state as arguments and returns the state and dispatch method. The reducer function takes the previous state and an action object as arguments and returns the new state. The action object has a type property that identifies the specific action to be performed.
The useReducer hook is a better choice than the useState hook for managing complex state logic because it makes it easier to reason about state changes and to avoid side effects. It is also more efficient, as it only recomputes the state that is actually needed.
Example of using useReducer:
Here is a simple example of how to use the useReducer hook to manage the state of a wallet:
import React, { useReducer } from 'react';
const reducer = (state, action) => {
switch (action.type) {
case 'BUY_INGREDIENTS':
return { ...state, wallet: state.wallet - 10 };
case 'SELL_MEAL':
return { ...state, wallet: state.wallet + 10 };
case 'CELEBRITY_VISIT':
return { ...state, wallet: state.wallet + 5000 };
default:
return state;
}
};
const initialState = {
wallet: 100,
};
const Wallet = () => {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div>
<h1>Wallet: {state.wallet}</h1>
<button onClick={() => dispatch({ type: 'BUY_INGREDIENTS' })}>Buy ingredients</button>
<button onClick={() => dispatch({ type: 'SELL_MEAL' })}>Sell meal</button>
<button onClick={() => dispatch({ type: 'CELEBRITY_VISIT' })}>Celebrity visit</button>
</div>
);
};
export default Wallet;
This code will render a button that allows the user to buy ingredients. When the user clicks the button, the dispatch method is called with an action object with the type BUY_INGREDIENTS
. The reducer function then updates the state to decrement the wallet amount by 10.
The same approach can be used to handle the other two actions, SELL_MEAL
and CELEBRITY_VISIT
.
Conclusion:
The useReducer hook is a powerful tool for managing complex state logic in React applications. It is more efficient and easier to reason about than the useState hook, making it a better choice for many situations.
What is useReducer?
The useReducer hook is a React hook that allows you to manage state in a more predictable and efficient way than the useState hook. It takes a reducer function and an initial state as arguments and returns the state and dispatch method.
The reducer function is a function that takes the previous state and an action object as arguments and returns the new state. The action object is an object that has a type property that identifies the specific action to be performed.
The dispatch method is a function that allows you to dispatch actions to the reducer function.
How useReducer differs from useState
The useReducer hook differs from the useState hook in a few key ways:
- useReducer takes a reducer function and an initial state as arguments, while useState only takes an initial state as an argument.
- useReducer returns the state and dispatch method, while useState only returns the state.
- useReducer makes it easier to reason about state changes and to avoid side effects.
- useReducer is more efficient, as it only recomputes the state that is actually needed.
When to use useReducer
You should use useReducer instead of useState when:
- You have complex state logic to manage.
- You need to avoid side effects.
- You need to improve the performance of your application.
Example of using useReducer
Here is a simple example of how to use the useReducer hook to manage the state of a counter:
import React, { useReducer } from 'react';
const reducer = (state, action) => {
switch (action.type) {
case 'INCREMENT':
return { count: state.count + 1 };
case 'DECREMENT':
return { count: state.count - 1 };
default:
return state;
}
};
const initialState = {
count: 0,
};
const Counter = () => {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div>
<h1>Counter: {state.count}</h1>
<button onClick={() => dispatch({ type: 'INCREMENT' })}>Increment</button>
<button onClick={() => dispatch({ type: 'DECREMENT' })}>Decrement</button>
</div>
);
};
export default Counter;
This code will render a counter with two buttons, one to increment the counter and one to decrement the counter. When the user clicks either button, the dispatch method is called with an action object with the type INCREMENT
or DECREMENT
. The reducer function then updates the state to increment or decrement the counter, respectively.
Conclusion
The useReducer hook is a powerful tool for managing state in React applications. It is more predictable and efficient than the useState hook, making it a better choice for many situations.
Which of the following statements is true about the useReducer hook?
The useReducer hook starts with an initial state and reducer function
That’s correct. The useReducer hook gets an initial state and a reducer function.
By now, you should have a
fairly good understanding of the useState hook and be able to practically apply it
to your solutions. However, the useState hook
does have its limitations. For example, the useState hook may become cumbersome
if you have complex state logic
that involves multiple sub-values or when the next state depends
on the previous one. In these situations
they useReducer hook can provide a much
better alternative. In this video, you’ll
learn more about use reducer and how it
differs from useState. You can think of the useReducer
as a superpower usestate. They useState hook starts
with an initial state, but they useReducer hook gets a reducer function in addition
to the initial state. This is beneficial because
the reducer functions second argument is
the action object. This object has
multiple type values, and based on each of
these types values, you can invoke the
dispatch function to perform a specific operation. Now, say the little
lemon restaurant is growing in
popularity and demand. As a result, keeping track of expenses is becoming an issue. Far, they have been calculating the income and
outgoings manually as they sell meals to
their customers and buy ingredients to
replenish the stock. Little lemon is
looking for a solution to this using React in order to keep track of expenses in their app and reduce the
burden on their staff. Because using the
useState hook would make the solution to this
unnecessarily extensive. This is a perfect
opportunity to implement the useReducer hook in
order to simply keep track of the cost of buying
ingredients and the income generated from selling the finished meals
to the customers. Now, let’s explore how to
implement the useReducer your hook in a code example to reinforce your understanding. Imagine I am coating
the expenses tracking application for little
lemon discussed earlier, using React and use reducer. With this app, I can
track two actions. The cost of buying ingredients
to prepare the meals and the little lemon restaurant
in the income from selling the finished meals to the customers and
the restaurant. For the sake of simplicity, I’ve only added two actions. Buy ingredients and sell meals. The reducer function takes in the previous state and an action and returns
the new state. The action type determines the specific action
of the reducer. Actions can have any form. By convention, it’s
common to pass objects with a type property
identifying the action. You should include the
minimal necessary information that the reducer needs to
compute the next state. You can find out more about
extracting state logic into a reducer in the additional readings at
the end of this lesson. Instead of using setState
like the useState hook, you use the dispatch method
of the useReducer hook. This accepts an
object literal with a single property
called type set to a matching action datatype whose behavior is defined
inside the reducer function. As I’m already serving
this app in the browser. Let me demonstrate how it works. When I press the shopping
for veggies button, the amount in the wallet
decreases by ten. When I press the server
meal to the customer, the amount in the wallet
increases by ten. With useReducer, you can define more types as many as you need. This way, you can
easily work with more complex logic
in your React apps. Something that might
be too difficult to rationalize when using useState. To explore this in practice, let’s add another action type. I’ll name it celebrity visit. This action should be triggered when a celebrity
visits the restaurant, which brings in $5,000 to the
restaurant when it happens. To make this work, I’ve added another action
type to the reducer function, and then another
button to trigger it. I’ll save my changes and preview the updated
app in the browser. There. It’s all
working as intended. Clicking the celebrity
visit button increases the wallet amount by 5,000
and it’s as simple as that. Now the little lemon restaurant will be able to keep track of their expenses so that they have a clear view of how much profit they’re making from
their business. In this video, you have learned about the useReducer hook, how it differs from
the useState hook, and why it can be a beneficial and more efficient solution in certain circumstances.
Reading: When to choose useReducer vs useState
Reading
The useState hook is best used on less complex data.
While it’s possible to use any kind of a data structure when working with useState, it’s better to use it with primitive data types, such as strings, numbers, or booleans.
The useReducer hook is best used on more complex data, specifically, arrays or objects.
While this rule is simple enough, there are situations where you might be working with a simple object and still decide to use the useState hook.
Such a decision might stem from the simple fact that working with useState can sometimes feel easier than thinking about how the state is controlled when working with useReducer.
It might help conceptualizing this dilemma as a gradual scale, on the left side of which, there is the useState hook with primitive data types and simple use cases, such as toggling a variable on or off.
At the end of this spectrum, there is the useReducer hook used to control state of large state-holding objects.
There’s no clear-cut point on this spectrum, at which point you would decide: “If my state object has three or more properties, I’ll use the useReducer hook”.
Sometimes such a statement might make sense, and other times it might not.
What’s important to remember is to keep your code simple to understand, collaborate on, contribute to, and build from.
One negative characteristic of useState is that it often gets hard to maintain as the state gets more complex.
On the flip side, a negative characteristic of useReducer is that it requires more prep work to begin with. There’s more setup involved. However, once this setup is completed, it gets easier to extend the code based on new requirements.
Conclusion
You learned about the decision-making process when choosing between useReducer and useState for working with different types of data.
Video: useRef to access underlying DOM
This video demonstrates how to use the useRef hook in React to focus the cursor into an input field.
The useRef hook is used to access and interact with a DOM element or to persist values across renders.
To use the useRef hook, you first need to create a ref object using the useRef() function. Then, you can assign the ref object to the input element using the ref attribute.
Once the ref object is assigned to the input element, you can access and interact with the DOM element using the current property of the ref object.
In the example video, the useRef hook is used to focus the cursor into an input field. This is done by accessing the focus() method on the current property of the ref object.
This technique can be used to focus the cursor into any DOM element, such as a text input field, a password field, or a button.
Tutorial on useRef to access underlying DOM in React
The useRef hook in React allows you to access and interact with DOM elements directly. This can be useful for a variety of tasks, such as focusing the cursor into an input field, scrolling to a specific element, or animating an element.
To use the useRef hook, you first need to create a ref object using the useRef() function. This returns an object with a single property, current, which is initially null.
Once you have a ref object, you can assign it to a DOM element using the ref attribute. When React renders the element, it will set the current property of the ref object to the DOM node.
You can then access and interact with the DOM node using the current property of the ref object. For example, you can call the focus() method to focus the cursor into the input field, or you can call the scrollIntoView() method to scroll to the element.
Here is an example of how to use the useRef hook to focus the cursor into an input field:
import React, { useRef } from 'react';
function FocusInput() {
const inputRef = useRef();
function handleClick() {
inputRef.current.focus();
}
return (
<div>
<input type="text" ref={inputRef} />
<button onClick={handleClick}>Focus Input</button>
</div>
);
}
In this example, the useRef() function is used to create a ref object called inputRef. This ref object is then assigned to the input element using the ref attribute.
When the user clicks the button, the handleClick() function is called. This function accesses the current property of the inputRef ref object and calls the focus() method to focus the cursor into the input field.
You can use the useRef hook to access and interact with any DOM element, not just input fields. For example, you could use it to scroll to a specific element, animate an element, or perform other DOM-related tasks.
Here are some additional tips for using the useRef hook:
- The useRef hook can be used to persist values across renders. For example, you could use it to store the scroll position of a window so that you can restore it the next time the component is rendered.
- The useRef hook can be used to access and interact with custom components. For example, you could use it to access the DOM node of a child component and call a method on it.
- Be careful not to overuse the useRef hook. It is generally best to only use it when you need to access or interact with the DOM directly.
What is the data type of the returned value from the useRef hook invocation?
An object
That’s correct! The returned value from the useRef hook invocation is an object.
Imagine the owner of
Little Lemon would like a search inventory
functionality that would focus the cursor into
the search input field. In this video, I
will demonstrate how to code this specific
requirement in a separate app so that you can focus on this particular
functionality. Here I have another
example app built using Create React App or CRA. Note that for the purpose
of this demonstration, I have made some
tweaks so that I can more easily showcase
the useRef hook. My starting app is just
a return statement with a fragment and inside of it an H1 that reads using useRef to access
the underlying DOM. As I’d like to demonstrate how they useRef hook is
used to access the DOM, I will use it to focus the
cursor into an input field. So let me start by
adding the input field. I will also add a button. Now that I’ve added an on-click
event handling attribute, I need to define the
focus input function to handle the button clicks. For the sake of simplicity, my click handler only accesses
the form input ref object, and then it accesses
the focus method on the current property which exist on the form
inputRef objects. But what is this object and
where does it come from? This object is the return value of invoking the useRef hook. So in this update
to my function, I’m invoking the React
User a function, and I’m saving a Ref object, that is the value returned from that function invocation to a variable named form input ref. Then setting the JSX
expression of form inputRef as the value of the ref
attribute on the input element. React will create
the input elements DOM node and render
it on the screen. This DOM node is
assigned as the value of the current property
of the ref object. This makes it possible to access the input DOM node and
all its properties and values using the syntax
form inputRef.current. Since I want to access the focus function on the
input elements DOM node, I’m using the syntax form
inputRef.current.focus. This allows me to
move the focus to the input field so that
it is ready to be typed into without the user having
to click tap or tap into it. This is now triggered
on a button click. To confirm that this works, I will save all my changes, go to my app being
served in the browser. Click outside of the input box and click the focus
input button. Great, everything is
working as expected. You have just
learned about using the useRef hook to hook
into the DOM and work with the properties of a
specific DOM node that you choose based
on the task at hand.
Reading: Custom hooks
Reading
React has some built-in hooks, such as the useState hook, or the useRef hook, which you learned about earlier. However, as a React developer, you can write your own hooks. So, why would you want to write a custom hook?
In essence, hooks give you a repeatable, streamlined way to deal with specific requirements in your React apps. For example, the useState hook gives us a reliable way to deal with state updates in React components.
A custom hook is simply a way to extract a piece of functionality that you can use again and again. Put differently, you can code a custom hook when you want to avoid duplication or when you do not want to build a piece of functionality from scratch across multiple React projects. By coding a custom hook, you can create a reliable and streamlined way to reuse a piece of functionality in your React apps.
To understand how this works, let’s explore how to build a custom hook. To put this in context, let’s also code a very simple React app.
The entire React app is inside the App component below:
import { useState } from "react";
function App() {
const [count, setCount] = useState(0);
function increment() {
setCount(prevCount => prevCount + 1)
}
return (
<div>
<h1>Count: {count}</h1>
<button onClick={increment}>Plus 1</button>
</div>
);
}
export default App;
This is a simple app with an h1 heading that shows the value of the count state variable and a button with an onClick event-handling attribute which, when triggered, invokes the increment() function.
The hook will be simple too. It will console log a variable’s value whenever it gets updated.
Remember that the proper way to handle console.log() invocations is to use the useEffect hook.
So, this means that my custom hook will:
- Need to use the useEffect hook and
- Be a separate file that you’ll then use in the App component.
How to name a custom hook
A custom hook needs to have a name that begins with use.
Because the hook in this example will be used to log values to the console, let’s name the hook useConsoleLog.
Coding a custom hook
Now’s the time to explore how to code the custom hook.
First, you’ll add it as a separate file, which you can name useConsoleLog.js, and add it to the root of the src folder, in the same place where the App.js component is located.
Here’s the code of the useConsoleLog.js file:
import { useEffect } from "react";
function useConsoleLog(varName) {
useEffect(() => {
console.log(varName);
}, [varName]);
}
export default useConsoleLog;
Using a custom hook
Now that the custom hook has been coded, you can use it in any component in your app.
Since the app in the example only has a single component, named App, you can use it to update this component.
The useConsoleLog hook can be imported as follows:
import useConsoleLog from “./useConsoleLog”;
And then, to use it, under the state-setting code, I’ll just add the following line of code:
useConsoleLog(count);
Here’s the completed code of the App.js file:
import { useState } from "react";
import useConsoleLog from "./useConsoleLog";
function App() {
const [count, setCount] = useState(0);
useConsoleLog(count);
function increment() {
setCount(prevCount => prevCount + 1);
}
return (
<div>
<h1>Count: {count}</h1>
<button onClick={increment}>Plus 1</button>
</div>
);
}
export default App;
This update confirms the statement made at the beginning of this reading, which is that custom hooks are a way to extract functionality that can then be reused throughout your React apps
Conclusion
You have learned how to name, build and use custom hooks in React.
Lab: Exercise: Create your own custom hook, usePrevious
Reading
Task
You’ve learned how to code a custom hook in React. In this code lab, you’ll practice writing a brand new custom hook.
The starter code for this app contains code that will display the day of the week within an h1 heading, for example: “Today is: Monday”. There is also a button under this heading, that reads “Get next day”.
When a user clicks on this button, the h1 heading updates so that the message shows the next day in the sequence.
Your task is to complete the custom hook named usePrevious so that the h1 heading shows both the current day and the previous current day before the update.
Note: Before you begin, make sure you understand how to work with the Coursera Code Lab for the Advanced React course.
Note: Use npm start to get the starting version of the app running in the browser.
Steps
Step 1
Open the App.js file and locate the usePrevious() function as in the below code snippet.
function usePrevious(val) {
}
Inside the usePrevious() function’s code block, invoke the useRef hook without any arguments, and assign this invocation to a variable named ref, declared using the const keyword.
Step 2
Next, inside the usePrevious() function declaration, add a call to the useEffect() hook.
Step 3
Now, pass two parameters, as an argument to the useEffect() call.
The first parameter should be an arrow function that doesn’t accept and arguments. Inside the arrow function’s body, assign the val value to the current property on the ref object.
The second parameter is the dependencies array. The dependencies array should list a single variable to be tracked – namely, the val variable.
Step 4
Add one more line to the body of the usePrevious() function declaration, specifying the return value of this function.
The usePrevious() function should return the ref.current value.
Conclusion
Save the changes and run the app.
Use the checklist below to verify that the completed app is behaving as required:
- It shows a heading that reads: “Today is: Monday”
- When the user clicks the “Get next day” button, this updates the heading, which now spans two lines.
- The first line of the updated heading now reads “Today is: Tuesday”, and the second line reads “Previous work day was: Monday”.
Reading: Solution: Create your own custom hook, usePrevious
Reading
Your task was to complete the custom hook named usePrevious so that the h1 heading shows both the current day and the previous current day before the update.
Here is the completed solution code for the App.js file:
import { useState, useEffect, useRef } from "react";
export default function App() {
const [day, setDay] = useState("Monday");
const prevDay = usePrevious(day);
const getNextDay = () => {
if (day === "Monday") {
setDay("Tuesday")
} else if (day === "Tuesday") {
setDay("Wednesday")
} else if (day === "Wednesday") {
setDay("Thursday")
} else if (day === "Thursday") {
setDay("Friday")
} else if (day === "Friday") {
setDay("Monday")
}
}
return (
<div style={{padding: "40px"}}>
<h1>
Today is: {day}<br />
{
prevDay && (
<span>Previous work day was: {prevDay}</span>
)
}
</h1>
<button onClick={getNextDay}>
Get next day
</button>
</div>
);
}
function usePrevious(val) {
const ref = useRef();
useEffect(() => {
ref.current = val;
}, [val]);
return ref.current;
}
Steps
Step 1
You should have located the usePrevious() function.
function usePrevious(val) {
}
Inside the usePrevious() function’s code block, you needed to invoke the useRef hook without any arguments, and assign this invocation to a variable named ref, declared using the const keyword.
function usePrevious(val) {
const ref = useRef();
}
Step 2
Next, inside the usePrevious() function declaration, you needed to add a call to the useEffect() hook.
function usePrevious(val) {
const ref = useRef();
useEffect();
}
Step 3
Then, you needed to pass two parameters as argumentsto the useEffect() function call.
The first parameter should have been an arrow function, without any arguments. Inside the arrow function’s body, you should have assigned the val value to the current property on the ref object.
The second parameter needed to be the dependencies array. The dependencies array needed to list a single variable – namely, the val variable.
function usePrevious(val) {
const ref = useRef();
useEffect(() => {
ref.current = val;
}, [val]);
}
Step 4
You needed to add one more line to the body of the usePrevious() function declaration, to specify the return value of that function.
The usePrevious() function should have returned the ref.current value, as follows:
function usePrevious(val) {
const ref = useRef();
useEffect(() => {
ref.current = val;
}, [val]);
return ref.current;
}
Practice Quiz: Self-review: Create your own custom hook, usePrevious
True or False: You code a custom hook when you want to avoid duplication.
True
Yes, it is correct that you code a custom hook when you want to avoid duplication.
AI assistant
True.
Custom hooks are a way to reuse stateful logic and functionality across multiple components in React. This can help to avoid code duplication and make your code more modular and maintainable.
For example, if you need to fetch data from an API in multiple components, you can create a custom hook to encapsulate the logic for fetching the data. This way, you can simply import the custom hook into each component and call it to fetch the data, without having to repeat the same code in each component.
Custom hooks can also be used to encapsulate other types of functionality, such as state management, form handling, and authentication.
Here is an example of a simple custom hook to fetch data from an API:
JavaScript
import { useState, useEffect } from 'react';
const useFetch = (url) => {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch(url);
const data = await response.json();
setData(data);
setLoading(false);
} catch (error) {
setError(error);
setLoading(false);
}
};
fetchData();
}, [url]);
return { data, loading, error };
};
To use the useFetch
custom hook in a component, you would simply import it and call it like this:
JavaScript
import { useFetch } from './useFetch';
const MyComponent = () => {
const { data, loading, error } = useFetch('https://api.example.com/users');
if (loading) {
return <p>Loading...</p>;
}
if (error) {
return <p>Error: {error.message}</p>;
}
return <ul>{data.map((user) => <li key={user.id}>{user.name}</li>)}</ul>;
};
This code is much more concise and maintainable than if we had to repeat the logic for fetching the data in each component that needed it.
Custom hooks are a powerful tool that can help you to write better React code. By using custom hooks, you can avoid code duplication, make your code more modular, and improve the maintainability of your codebase.
Let’s imagine you code a custom hook, called for example useNext, on a separate file named useNext.js What’s the minimum requirement for the custom useNext hook to be a valid hook?
The custom hook should use at least one built-in React hook
Correct, that’s the minimum requirement for the custom hook to be valid
AI assistant
The minimum requirement for the custom useNext hook to be a valid hook is that it should use at least one built-in React hook.
Custom hooks are functions that start with the word “use” and may call other hooks. The “use” naming convention mainly allows the linter to find bugs in how these hooks are used, for example scenarios where their usage goes against the rules of Hooks.
While it is advisable to always return a value from a custom hook, it is not strictly required. There are some cases where it may make sense to return nothing from a custom hook, such as if the hook is only used to perform side effects.
Similarly, while it is common to receive parameters in custom hooks, it is also not strictly required. Some custom hooks may not need any parameters, such as a custom hook to manage global state.
Here is an example of a valid custom hook that uses the built-in useState
hook:
JavaScript
import { useState } from 'react';
function useNext() {
const [count, setCount] = useState(0);
const next = () => {
setCount(count + 1);
};
return { next, count };
}
This custom hook can be used in a component like this:
JavaScript
function MyComponent() {
const { next, count } = useNext();
return (
<div>
<h1>{count}</h1>
<button onClick={next}>Next</button>
</div>
);
}
When the user clicks the button, the next()
function will be called, which will increment the count
state variable. The component will then re-render, displaying the updated count.
Custom hooks are a powerful tool that can help you to write more modular and reusable React code. By following the simple rules for creating valid custom hooks, you can ensure that your hooks will work as expected and be compatible with other React hooks.
In the previous exercise, you were given a task to create your own custom hook, usePrevious. What was being returned from the usePrevious function declaration?
ref.current
Correct. The value that needed to be returned from the usePrevious hook was the current property on the ref object.
AI assistant
The usePrevious
function declaration returns the value of the ref.current
property. The ref
object is a mutable ref object that can hold any value, similar to an instance property on a class.
In the usePrevious
hook, the ref
object is used to store the previous value of the input value. This is done by updating the ref.current
property whenever the input value changes. Then, the hook returns the current value of the ref.current
property, which is the previous value of the input value.
Here is the code for the usePrevious
hook:
JavaScript
import { useRef, useEffect } from 'react';
export function usePrevious<T>(value: T): T | undefined {
const ref = useRef();
useEffect(() => {
ref.current = value;
}, [value]);
return ref.current;
}
This hook can be used in a component like this:
JavaScript
const MyComponent = () => {
const [count, setCount] = useState(0);
const previousCount = usePrevious(count);
return (
<div>
<h1>{count}</h1>
<p>Previous count: {previousCount}</p>
</div>
);
};
This code will render a counter with a label that shows the previous value of the count. When the user clicks the button to increment the count, the setCount()
function will be called, which will update the count state variable. The component will then re-render, displaying the updated count and the previous value of the count.
The usePrevious
hook is a useful tool for tracking the previous value of a state variable. This can be used for various purposes, such as implementing undo/redo functionality, comparing changes in data over time, or detecting changes in a component’s state.
Practice Quiz: Knowledge check: Advanced Hooks
True or false: useReducer is a reducer function that takes in the initial state and an action and returns the new state.
True
Correct! The reducer function takes in the initial state and an action and returns the new state.
AI assistant
True. useReducer is a React Hook that lets you manage state using a reducer function. The reducer function takes in the current state and an action object, and returns the new state. The action object describes what change should be made to the state.
Here is an example of a useReducer hook:
JavaScript
import React, { useReducer } from "react";
const initialState = {
count: 0
};
const reducer = (state, action) => {
switch (action.type) {
case "INCREMENT":
return { ...state, count: state.count + 1 };
case "DECREMENT":
return { ...state, count: state.count - 1 };
default:
return state;
}
};
const Counter = () => {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: "INCREMENT" })}>Increment</button>
<button onClick={() => dispatch({ type: "DECREMENT" })}>Decrement</button>
</div>
);
};
In this example, the reducer function takes in the current state and an action object, and returns the new state. The action object describes what change should be made to the state. In this case, the action object can be either “INCREMENT” or “DECREMENT”.
The useReducer hook is a powerful tool for managing state in React applications. It allows you to write more modular and reusable code. It also makes it easier to debug your code, as you can track the changes to your state over time.
True or false: The useState hook is best suited for complex state logic or when the next state depends on the previous one.
False
Correct! Actually, the useReducer hook is better suited for those use-cases
AI assistant
False. The useState hook is best suited for simple state logic, such as managing the value of a form input or the visibility of a component. It is not well-suited for complex state logic or when the next state depends on the previous one.
For complex state logic, it is recommended to use the useReducer hook. The useReducer hook allows you to use a reducer function to manage your state. The reducer function takes in the current state and an action object, and returns the new state.
Here is an example of a useReducer hook:
JavaScript
import React, { useReducer } from "react";
const initialState = {
count: 0
};
const reducer = (state, action) => {
switch (action.type) {
case "INCREMENT":
return { ...state, count: state.count + 1 };
case "DECREMENT":
return { ...state, count: state.count - 1 };
default:
return state;
}
};
const Counter = () => {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: "INCREMENT" })}>Increment</button>
<button onClick={() => dispatch({ type: "DECREMENT" })}>Decrement</button>
</div>
);
};
In this example, the reducer function takes in the current state and an action object, and returns the new state. The action object describes what change should be made to the state. In this case, the action object can be either “INCREMENT” or “DECREMENT”.
The useReducer hook is a powerful tool for managing state in React applications. It allows you to write more modular and reusable code. It also makes it easier to debug your code, as you can track the changes to your state over time.
When to use the useState hook
The useState hook is best suited for simple state logic, such as:
- Managing the value of a form input
- Managing the visibility of a component
- Managing the selected item in a list
When to use the useReducer hook
The useReducer hook is best suited for complex state logic, such as:
- Managing the state of a complex form
- Managing the state of a game
- Managing the state of a real-time application
If you are unsure which hook to use, it is generally recommended to start with the useState hook. If you find that your state logic is becoming too complex, you can always switch to the useReducer hook later.
A common scenario for using the useRef hook is to…
…focus the cursor into an input field.
Correct. That’s a “textbook example” of the useRef hook in use.
AI assistant
A common scenario for using the useRef hook is to focus the cursor into an input field.
The useRef hook can be used to access a DOM element directly, without having to go through React. This is useful for cases where you need to control the element directly, such as when you need to focus the cursor into an input field.
Here is an example of how to use the useRef hook to focus the cursor into an input field:
JavaScript
import React, { useRef } from "react";
const Input = () => {
const inputRef = useRef(null);
const focusInput = () => {
inputRef.current.focus();
};
return (
<div>
<input ref={inputRef} />
<button onClick={focusInput}>Focus Input</button>
</div>
);
};
In this example, the inputRef
ref is used to store a reference to the input element. The focusInput()
function then uses the current
property of the ref to access the input element and call the focus()
method.
The useRef hook can also be used for other purposes, such as:
- Controlling a component’s state
- Handling side effects
- Memorizing expensive operations
However, focusing the cursor into an input field is one of the most common scenarios for using the useRef hook.
True or false: Building your own Hooks lets you extract component logic into reusable functions
True
Correct! This is a true statement.
AI assistant
True. Building your own Hooks lets you extract component logic into reusable functions.
Hooks are a feature in React that lets you use state and other React features without writing a class. You can also create your own Hooks to extract component logic into reusable functions.
This can be useful for a number of reasons:
- It makes your code more modular and reusable.
- It makes your code easier to understand and maintain.
- It can help you to avoid common coding mistakes.
Here is an example of a custom Hook:
JavaScript
import React, { useState } from "react";
const useCounter = (initialState) => {
const [count, setCount] = useState(initialState);
const increment = () => {
setCount(count + 1);
};
const decrement = () => {
setCount(count - 1);
};
return [count, increment, decrement];
};
const Counter = () => {
const [count, increment, decrement] = useCounter(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
</div>
);
};
This custom Hook can be used to manage the state of a counter in any React component. For example, you could use it in a component that renders a button that increments a counter, or in a component that renders a list of items and shows the total number of items in the list.
Building your own Hooks is a great way to make your React code more modular, reusable, and maintainable.
The useState hook gives us a reliable way to…
… deal with state updates in React components.
Correct! Indeed, the useState hook gives us a reliable way to deal with state updates in React components.
AI assistant
The useState hook gives us a reliable way to deal with state updates in React components.
The useState hook is a React Hook that lets you manage state in functional components. It returns an array with two values: the current state and a function to update it. The Hook takes an initial state value as an argument and returns an updated state value whenever the setter function is called.
Here is an example of how to use the useState hook:
JavaScript
import React, { useState } from "react";
const Counter = () => {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
};
In this example, the useState
hook is used to manage the state of the counter. The initial state of the counter is 0. The setCount
function is used to update the state of the counter.
When the user clicks the button, the setCount
function is called with a new value of count + 1
. This updates the state of the counter, and the component is re-rendered.
The useState hook is a reliable way to deal with state updates in React components. It is easy to use and understand, and it provides a number of benefits, such as:
- It makes it easy to manage state in functional components.
- It makes it easy to track changes to state over time.
- It makes it easy to debug state-related problems.
If you are building React applications, I recommend that you use the useState hook to manage state in your components.
Video: Module summary: React Hooks and Custom Hooks
Key lessons learned:
- useState hook: used to work with state in a React component
- useEffect hook: used to perform side effects in React components
- rules of hooks and React: hooks should only be called from React component functions and at the top level, and multiple hooks can be called inside a component in the same sequence
Skills gained:
- fetching JSON data from the web using React
- using the useReducer hook to track state
- using refs to go beyond the virtual DOM and access the underlying DOM elements
- creating custom hooks
Next steps:
- Learn about JSX in the next module
Well done. You’ve
reached the end of this module on React
hooks and custom hooks. Throughout this module,
you’ve explored hooks and React in
depth and covered many important concepts and practical applications that will benefit you as you progress
through the course. It’s now time to recap the key lessons you’ve learned
and skills you’ve gained. Your first lesson focused
on the useState hook, which is used to work with
state in a React component. You’ve explored how to perform
array destructuring using the useState hook and
update state when using new state through the
state updating function, and even how to change
state and response to user generated events
like button clicks. You then worked through a
detailed demonstration, learning how to use the useState
hook within a component, including how to declare, read, and update state. Next, you learned about
side effects in relation to another important hook,
the useEffect hook. You discovered that side effects make a function impure with impure functions
performing side effects such as invoking console log, fetch or the browser’s
geolocation functionality. In addition to learning about the useEffect hook
theoretically. You learned how to use
the useEffect hook to perform side effects within
functional components and to control when the
useEffect function is run using the dependency array through a practical
demonstration. Recall that the dependency array determines when the useEffect
hook will be invoked. Following the completion of
Lesson 1 of this module, you should now be
better positioned to work with state and React and to handle side
effects in your components. The second lesson of
this module focused on the rules of hooks and fetching
JSON data from the web. First, you were introduced
to the rules of hooks and React
and unpacked them. These rules are that
you should only call hooks from a React
component function and at the top level of a React component function or allowed to call
multiple state hooks or effect hooks inside a
component and should make multiple hook calls
in the same sequence. Next, in relation to
the fetch function, you learned about the
delegation of duties in JavaScript referred to as
asynchronous JavaScript. You also learned about the
fetch function itself, which is a function that looks like it’s part of JavaScript, but it’s actually a way to call a browser API from JavaScript. This led up to the
lesson on fetching data using the state
and effect hooks. You worked through a
demonstration where a call to the fetch API was used to get data from the web using React. Now that you’ve
completed this lesson, you should have greater
insight into what happens if a developer doesn’t follow
the rules of hooks and React, and be able to
describe how data is fetched in both
JavaScript and React. In the third lesson
of this module, you learned about
the useReducer hook and that it differs from the useState hook
because it gets a reducer function in addition
to the initial state. You learned that the
useReducer hook could be used in cases where they
useState hook would be inefficient such
as when you have complex state logic and how to implement the useReducer
hook in your code. You were also introduced to the concept of refs and
how they can be used to go beyond the
virtual DOM and access the underlying DOM elements as well as other applications, and have the
opportunity to explore coding your own custom hooks. By completing this lesson, you should be able to use
the useReducer hook to track state as well as roll out your own hooks in
your React apps. You’re making
excellent progress. Now that you have a solid
grasp of working with hooks, it’s time to take a
deep dive into JSX, which I look forward to guiding you through in the next module.
Quiz: Module quiz: React Hooks and Custom Hooks
How is array destructuring relevant to hooks in React?
It is a way to get individual items from an array of items, and save those individual items as separate components.
Correct. It is a way to get individual items from an array of items, and save those individual items as separate components.
AI assistant
The correct answer is: It is a way to get individual items from an array of items, and save those individual items as separate components.
Array destructuring is a way of unpacking an array into its individual elements. This can be useful when working with React hooks, as it allows you to get the individual items from the array returned by a hook and save them as separate variables.
For example, the following code uses the useState
hook to create a state variable called count
and a function called setCount
:
JavaScript
const [count, setCount] = useState(0);
The useState
hook returns an array, with the first element being the current value of the state variable and the second element being a function that can be used to update the state variable.
Using array destructuring, you can unpack this array into its individual elements:
JavaScript
const [count, setCount] = useState(0);
// count is now the current value of the state variable
// setCount is the function that can be used to update the state variable
This makes it easier to work with the state variable, as you can now refer to it by its name (count
) instead of having to access it through the array (useState(0)[0]
).
Array destructuring can also be used to get individual items from the array returned by other hooks, such as the useEffect
hook and the useContext
hook.
In addition to making it easier to work with hooks, array destructuring can also be used to improve the readability of your code. By unpacking arrays into their individual elements, you can make it clear what data is being used by your code.
Therefore, array destructuring is relevant to hooks in React because it allows you to get individual items from the array of items returned by a hook and save those individual items as separate variables. This can make it easier to work with hooks and improve the readability of your code.
Is the following paragraph correct?
With array destructuring, you are free to give any variable name to the items that you destructure from an array. Contrary to that, when destructuring objects, you have to destructure a property of an object using that exact property’s name as the name of the destructured variable.
Yes
That’s right, the paragraph is correct.
AI assistant
Yes, the paragraph is correct.
With array destructuring, you can give any variable name to the items that you destructure from an array. For example, the following code destructures the first and second items from an array and assigns them to the variables first
and second
:
JavaScript
const array = [1, 2];
const [first, second] = array;
console.log(first); // 1
console.log(second); // 2
In this example, the variables first
and second
do not have to have the same names as the items in the array.
However, with object destructuring, you have to destructure a property of an object using that exact property’s name as the name of the destructured variable. For example, the following code destructures the name
and age
properties from an object and assigns them to the variables name
and age
:
JavaScript
const object = { name: "John Doe", age: 30 };
const { name, age } = object;
console.log(name); // John Doe
console.log(age); // 30
In this example, the variables name
and age
must have the same names as the properties in the object. If you try to destructure a property using a different name, you will get an error.
The reason for this difference is that arrays are ordered collections of items, while objects are unordered collections of key-value pairs. When you destructure an array, you are simply getting the items from the array in the order they appear. However, when you destructure an object, you are getting the values of specific properties in the object. In order to get the value of a property, you need to use the name of that property.
The useEffect hook is a way to:
handle a side effect.
That’s correct! The name of the useEffect hook is closely related to the concept of an effect, or more precisely, of a side effect.
AI assistant
The correct answer is: handle a side effect.
The useEffect
hook is a React hook that lets you perform side effects in function components. Side effects are actions that can affect the state of the component or the DOM outside of the normal React rendering process. Some examples of side effects include:
- Fetching data from an API
- Setting timers
- Updating the DOM directly
- Subscribing to events
The useEffect
hook takes a function as its argument. This function is called after the component is rendered. The function can perform any side effects that you need.
For example, the following code uses the useEffect
hook to fetch data from an API:
JavaScript
useEffect(() => {
fetch("https://api.example.com/data")
.then(response => response.json())
.then(data => setData(data));
}, []);
This code will fetch data from the API when the component is first rendered. The data will then be stored in the data
state variable.
The useEffect
hook can also be used to perform side effects that are based on changes to the component’s state or props. For example, the following code uses the useEffect
hook to update the document title when the count
state variable changes:
JavaScript
useEffect(() => {
document.title = `Count: ${count}`;
}, [count]);
This code will update the document title whenever the count
state variable changes.
The useEffect
hook is a powerful tool that can be used to handle a wide variety of side effects. By using the useEffect
hook, you can keep your React components clean and maintainable.
The other options are not correct. The useEffect
hook is not used to handle one-way data flows or visual effects.
Which answer is correct about the following code snippet?
useEffect( () => {
if (data !== ”) {
setData(‘test data’)
}
})
AI assistant
The correct answer is: This code is breaking the rules of hooks
The reason this code is breaking the rules of hooks is because the setData
function is being called inside a conditional statement. This is not allowed because it can lead to unexpected behavior.
When a hook is called, React creates a dependency array. This dependency array is a list of values that the hook depends on. If any of the values in the dependency array change, the hook will be called again.
In the case of the code snippet above, the dependency array is empty. This means that the useEffect
hook will be called every time the component is rendered.
The problem with this is that the setData
function is being called inside a conditional statement. This means that the setData
function will not always be called when the component is rendered. For example, if the data
variable is empty, the setData
function will not be called.
This can lead to unexpected behavior because the useEffect
hook will not be aware that the data
variable has changed. As a result, the useEffect
hook will not update the state of the component.
To fix this problem, you can remove the conditional statement from the useEffect
hook. For example, the following code is correct:
JavaScript
useEffect(() => {
setData('test data');
}, []);
This code will always call the setData
function when the component is rendered. As a result, the useEffect
hook will always update the state of the component.
In general, it is a good idea to avoid using conditional statements inside useEffect
hooks. If you need to use a conditional statement, you can use a ternary operator instead. For example, the following code is correct:
JavaScript
useEffect(() => {
setData(data !== '' ? 'test data' : data);
}, []);
This code uses a ternary operator to determine whether to call the setData
function. As a result, the useEffect
hook will only update the state of the component if the data
variable is not empty.
Choose an example of a side-effect with which you’d need to use a useEffect hook:
Run a Fetch API call in React.
Correct. The call to the Fetch API is a side-effect, and you should use the useEffect hook to handle it.
AI assistant
The correct answer is: Run a Fetch API call in React.
The useEffect
hook is used to perform side effects in React components. Side effects are actions that can affect the state of the component or the DOM outside of the normal React rendering process.
Fetching data from an API is a common side effect that is often performed using the useEffect
hook. For example, the following code uses the useEffect
hook to fetch data from an API and store the data in the data
state variable:
JavaScript
useEffect(() => {
fetch("https://api.example.com/data")
.then(response => response.json())
.then(data => setData(data));
}, []);
This code will fetch data from the API when the component is first rendered. The data will then be stored in the data
state variable.
The other options are not examples of side effects. Updating the value of a state variable in a child component is not a side effect because it does not affect the state of the parent component. Rendering some prop values on the screen is not a side effect because it is part of the normal React rendering process.
Therefore, the correct answer is Run a Fetch API call in React.
Complete the sentence:
The useState hook starts with an initial state, but…
the useReducer hook gets a reducer function in addition to the initial state.
Correct. The useState hook starts with an initial state, but the useReducer hook gets a reducer function in addition to the initial state.
AI assistant
The correct answer is: the useReducer hook gets a reducer function in addition to the initial state.
The useState
hook is a React hook that is used to manage the state of a component. The useState
hook takes an initial state as its argument and returns a state variable and a function that can be used to update the state variable.
The useReducer
hook is a React hook that is also used to manage the state of a component. The useReducer
hook takes an initial state and a reducer function as its arguments. The reducer function is a function that takes the current state and an action and returns the next state.
The useReducer
hook is more powerful than the useState
hook because it allows you to have more control over how the state of your component is updated. For example, you can use the useReducer
hook to implement complex state management patterns, such as Redux.
Therefore, the complete sentence is:
The
useState
hook starts with an initial state, but theuseReducer
hook gets a reducer function in addition to the initial state.
True or false: useRef is a custom hook in React.
No
Correct. The useRef hook is a built-in hook, just like some other hooks are, such as the useState or useReducer.
AI assistant
False. useRef
is a built-in hook in React. It is used to create a reference to a DOM element or other mutable object. The useRef
hook does not accept any arguments and returns a mutable ref object. The current
property of the ref object can be used to read or write the value of the reference.
Custom hooks are functions that can be used to create reusable pieces of state and logic. Custom hooks are often used to abstract away complex functionality or to provide a more consistent API for interacting with the React state management system.
For example, the following code uses the useRef
hook to create a reference to a DOM input element:
JavaScript
const inputRef = useRef(null);
function focusInput() {
inputRef.current.focus();
}
return (
<input ref={inputRef} />
);
In this example, the inputRef
variable is a ref object that can be used to access the DOM input element. The focusInput()
function uses the current
property of the inputRef
object to focus the input element.
JavaScript is a single-threaded language, meaning…
…it can only do a single thing at any given time.
Correct. This is a true statement.
AI assistant
The correct answer is: …it can only do a single thing at any given time.
JavaScript is a single-threaded language, meaning that it can only execute one line of code at a time. This is in contrast to multi-threaded languages, which can execute multiple lines of code simultaneously.
The single-threaded nature of JavaScript can have implications for the performance of your code. For example, if you have a long-running operation, such as a fetch request, it can block the execution of the rest of your code. This can lead to a perceived slowdown in the responsiveness of your application.
However, the single-threaded nature of JavaScript also has some advantages. For example, it makes it easier to reason about the state of your code. Because only one line of code can be executed at a time, you don’t have to worry about race conditions or other concurrency issues.
In the context of React, the single-threaded nature of JavaScript is not a major concern. React uses a number of techniques to ensure that your code is executed in a performant manner. For example, React uses a virtual DOM to diff the state of your components. This means that only the parts of the DOM that have changed need to be updated.
As a result, you don’t need to worry about the single-threaded nature of JavaScript when using React. However, it is important to be aware of the implications of the single-threaded nature of JavaScript when writing your own code.
Which statement is correct about the following code snippet:
import { useEffect } from “react”;
function useConsoleLog(varName) {
useEffect(() => {
console.log(varName);
});
}
export default useConsoleLog;
Choose the correct statement below.
This is an example of a custom hook.
Correct. This is an example of a custom hook.
AI assistant
The correct answer is: This is an example of a custom hook.
A custom hook is a function that can be used to create reusable pieces of state and logic. Custom hooks are often used to abstract away complex functionality or to provide a more consistent API for interacting with the React state management system.
In the code snippet above, the useConsoleLog
function is a custom hook that can be used to log the value of a variable to the console. The useConsoleLog
hook takes a variable name as its argument and uses the useEffect
hook to log the value of the variable to the console whenever the value of the variable changes.
The useConsoleLog
hook is not an example of an implicit or explicit state-updating function. Implicit state-updating functions are functions that update the state of a component without explicitly calling the setState
method. Explicit state-updating functions are functions that explicitly call the setState
method to update the state of a component.
The useConsoleLog
hook does not update the state of any component. Instead, it simply logs the value of a variable to the console. Therefore, the useConsoleLog
hook is not an example of an implicit or explicit state-updating function.
In summary, the correct statement about the code snippet is that it is an example of a custom hook.
Find the error in this code:
import {useState} from “react”;
export default function App() {
const [restaurantName, setRestaurantName] = useState(“Lemon”);
function updateRestaurantName() {
useRestaurantName(“Little Lemon”);
};
return (
{restaurantName}
Update restaurant name
);
};
The code inside the updateRestaurantName() function definition should not invoke useRestaurantName(“Little Lemon”)
Correct. The code inside the updateRestaurantName() function should invoke setRestauranName(“Little Lemon”).
AI assistant
The error in the code is that the updateRestaurantName()
function is calling the useRestaurantName()
hook instead of the setRestaurantName()
function.
The correct code is:
JavaScript
import {useState} from "react";
export default function App() {
const [restaurantName, setRestaurantName] = useState("Lemon");
function updateRestaurantName() {
setRestaurantName("Little Lemon");
};
return (
<div>
<h1>{restaurantName}</h1>
<button onClick={updateRestaurantName}>
Update restaurant name
</button>
</div>
);
};
The useRestaurantName()
hook is a state-setting function that is returned by the useState()
hook. The setRestaurantName()
function is the actual function that is used to update the value of the restaurantName
state variable.
In the original code, the updateRestaurantName()
function is calling the useRestaurantName()
hook with the argument "Little Lemon"
. This is not correct because the useRestaurantName()
hook is not a function that can be used to update the value of a state variable.
The correct way to update the value of the restaurantName
state variable is to call the setRestaurantName()
function with the new value. In the corrected code, the updateRestaurantName()
function calls the setRestaurantName()
function with the argument "Little Lemon"
. This will update the value of the restaurantName
state variable to "Little Lemon"
.
Reading: Additional resources
Reading
Below is a list of additional readings as you continue to explore ‘React hooks and custom hooks’.
In particular, to complement your learning in the ‘Advanced hooks’ lesson, you can work through the following:
- The useReducer hook reference in the React docs discusses the basics of useReducer, along with specifying initial state and lazy initialization.
- The React docs also has a reference on using the useRef hook which is a great example of various options that are available when working with the useRef hook.
- The Reusing Logic with Custom Hooks reference in the React docs discusses the dynamics of custom hooks and provides a few practical examples to complement the theory behind them.