React Simplified_ The Essential Guide for Beginners
React Simplified_ The Essential Guide for Beginners
Introduction to React 3
💡
What is React? 3
💡
Why React 3
Getting Started with React 3
Step1: Set up Your HTML File 4
What is CreateElement 5
Create and Render an Element 5
Adding Properties. 6
Nesting Elements 6
What is JSX 9
Setting up a React environment 12
Recommended Tools for React Development: 12
Start a New React Project 14
Application Structure 14
JSX Expressions 19
What is jsx Fragment 21
Components 22
Create Your First Component 23
Styling in React 24
Props 26
Destructuring Props 32
List Items 32
Iterating with the Map() Method 33
Conditional Rendering 37
Other examples of Conditional Rendering 40
JSX Tags must be Closed 42
JSX Attributes must use CamelCase 42
Conditionals in JSX 44
State Management in React 44
Use the State in JSX 46
State management in Forms 46
How State Works in Forms 48
Lifting State in React 51
Managing Side Effects with the useEffect Hook 55
API Requests 55
The dependency array 56
Local Storage 57
Conclusion 60
Introduction to React
What is React?
React is an open-source JavaScript library developed by Facebook in 2013 for building
user interfaces, particularly for web applications. Facebook developed React because
they had a problem with the state of messages where read messages would still display
the unread count.
React comes with its own rules, and to understand React, you need to adhere to these
rules and understand how React renders when an application loads. Once you
understand these concepts, learning React becomes a breeze
💡Why React
React is one of the most popular frameworks and one of the most in-demand libraries. It
also relies heavily on JavaScript, so if you are proficient in JavaScript, learning React
will prove to be easier.
React is also an evolving library with a strong vibrant, active community who are
continuously improving its features.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,
initial-scale=1.0">
<title>React CDN Example</title>
<!-- React Library -->
<script
src="https://unpkg.com/react@17/umd/react.development.js"></script>
<!-- React DOM Library -->
<script
src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></s
cript>
</head>
<body>
<div id="root"></div>
<script>
// Your React code will go here
</script>
</body>
</html>
In the head section, we have two script tags for loading React and ReactDom from a
CDN. Then a div with the id = root. This is where our react application will be rendered.
What is CreateElement
CreateElement is a function used by React to create React elements. React elements
are the building blocks of React. The basic syntax of creating a React element with the
createElement function looks like this:
● type - this can be a string for HTML elements (i.e. “div”, “h1”), etc.
When you open the index.html file with your browser, you can see the content
rendered on your browser.
Congratulations, you have just created your first React App.
Adding Properties.
Our H1 element at the moment does not have any properties, let's fix that, add an id ==
header
Now, if you inspect with Developer tools, you can see the ID has been applied.
Nesting Elements
You can also nest createElement call to create more elements. For example, let's add
more elements and enclose them with a div.
ReactDOM.render(divElement, document.getElementById('root'));
const divElement = React.createElement('div', {id: "container"},
element, element2); This creates a <div> element with the ID "container". Inside this
div, we are passing the 2 elements as children.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,
initial-scale=1.0">
<title>React CDN Example</title>
<!-- React Library -->
<script
src="https://unpkg.com/react@17/umd/react.development.js"></script>
<!-- React DOM Library -->
<script
src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></s
cript>
</head>
<body>
<div id="root"></div>
<script>
const element = React.createElement('h1', {id
:"header"},"Hello World!");
const element2 = React.createElement('p', {id :"paragraph"},
"This is a paragraph.");
const divElement = React.createElement('div', {id
:"container"},element,element2);
ReactDOM.render(divElement, document.getElementById('root'));
</script>
</body>
</html>
This method of creating a React application is a great way to understand how React
works under the hood but for larger applications, you would typically use JSX. JSX
syntax is the recommended way to create React applications
JSX is a syntax extension for JavaScript that lets you write HTML-like markup inside
JavaScript files. JSX is easier to read and write because it utilizes pure JavaScript. So if
you have a solid foundation in JavaScript, Learning React will not be that difficult.
For example, if we were to use a component, the previous code we have just written in
JSX, we will have something like this;
function MyComponent() {
return (
<div id="container">
<h1 id="header">Hello World!</h1>
<p id="paragraph">This is a paragraph.</p>
</div>
);
}
const element = (
<div id="container">
<h1 id="header">Hello !</h1>
<p id="paragraph">Hello</p>
</div>
);
ReactDOM.render(element, document.getElementById("root"));
</script>
</body>
</html>
This code will not work because the JSX code needs to be compiled. Compiling is
important because browsers don't understand JSX code, so tools like Babel transform
the code into a format suitable for browsers to read.
To fix this issue, include a compiler such as Babel and specify that the JSX code should
be transpiled. Update the code as follows:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width,
initial-scale=1.0" />
<title>React CDN Example</title>
<!-- React Library -->
<script
src="https://unpkg.com/react@17/umd/react.development.js"></script>
<!-- React DOM Library -->
<script
src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></s
cript>
<!-- Babel for JSX -->
<script
src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
const name = "World";
const message = "This is a dynamic paragraph.";
const element = (
<div id="container">
<h1 id="header">Hello {name}!</h1>
<p id="paragraph">{message}</p>
</div>
);
ReactDOM.render(element, document.getElementById("root"));
</script>
</body>
</html>
You might have noticed when we injected the javascript variable inside our HTML
markup, we used curly braces.
In JSX, if you need to add JavaScript expressions or variables inside your HTML-like
markup, you need to wrap the JS code inside curly braces {}. The curly braces tell JSX
that the code inside the braces is Javascript code and not plain text.
Setting up a React environment
We have seen how to create a React app using a CDN, along with createElement,
ReactDOM, and Babel. However, this method is not recommended for production
applications, as it does not scale well for larger projects.
Luckily, several frameworks and tools exist that provide built-in support for React and
abstract away the complexities of setting up a build process. These tools enable
developers to focus on writing code rather than managing configurations.
1. Vite:Vite is a modern build tool that provides a fast and efficient development
environment for React applications.
2. Create React App (CRA):Create React App is a widely used tool that sets up a
new React project with a solid default configuration.
In this guide, we will use Create React App to create our React applications. If you dont
fancy a local development environment, you can use https://codesandbox.io to host
your code.
Head over to https://codesandbox.io/ and create an account. Once you are logged in.
On your dashboard, create a new React application using Vite.
If you prefer a local environment, then you should have Node.js installed. React
requires Node.js to run its development server and build the project. You can download
the latest stable version of Node.js from Node.js official website.
Start a New React Project with Create-react app
To create a new project, issue the npx create-react app command.
Once the installation is complete, cd into the app and issue the npm start command
cd hello-react
npm start
Application Structure
The app structure looks like this:
Whether you use a local development environment or an online tool like CodeSandbox,
the structure of the application will be the same. Both methods provide a similar setup,
with files like index.js, App.js, and index.html acting as the foundation of your React
app.
In this guide, we will use CodeSandbox but for larger applications, a local development
environment offers more control and is preferred.
In the public folder, we have an index.html file which looks like this:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,
initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
<title>React App</title>
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
</body>
</html>
The index.html file is a standard HTML file, except that it includes a <div
id="root"></div>. In React, this <div id="root"></div> serves as the mounting point
where React renders your application.
All the content will be injected into this div. Unlike in a traditional app, where you would
select each element using methods like getElementById or querySelector, React uses
the ReactDOM.render() method to render components into this div. This process is
handled in the index.js file.
In your index.js file, you have the code below
root.render(
<StrictMode>
<App />
</StrictMode>
);
The virtual DOM allows React to make updates more efficiently by calculating changes
in memory and then updating only the necessary parts of the actual DOM.
Once we get a reference to the root, we call createRoot to create a React root. The
React root will display content in the browser. Lastly, we render the App component.
The App component introduces us to the JSX (JavaScript XML) syntax. React uses
JSX syntax to describe the UI. Most of the code in React applications is written in JSX.
As you can see, JSX looks similar to regular HTML. Behind the scenes, JSX is
transformed into JavaScript function calls (e.g., React.createElement) before being
rendered to the DOM.
At the top of the file, we can see import "./styles.css"; statement that imports a
CSS file that styles the component. In a regular HTML file, we use class to apply style,
but in JSX, the equivalent is className . The className="App" is used to apply
CSS styles defined in the styles.css file. In JSX, class is a reserved keyword in
JavaScript, so it can't be used as an attribute name.
To prevent conflicts with the JavaScipt language, JSX uses className instead of
class to define CSS classes on elements.
A React component is a regular javascript function or class that returns JSX. In the
return statement, we have the JSX code that describes the UI. The UI has a div element
with two headings: an <h1> and an<h2>.
In our case, we have seen the App component imported in the index.js file.
// index.js
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
root.render(
<StrictMode>
<App />
</StrictMode>
);
If you don't use export default, then you would then have to use a named export like this
JSX Expressions
Earlier, we saw that we need to enclose any Javascript code with curly braces { }
Inject them into h1 and p tags respectively. The elements should be contained in a div
element. The App component now looks like this.
import "./styles.css";
import "./styles.css";
When we do this, we run into some errors, The error message “Adjacent JSX
elements must be wrapped in an enclosing tag. “ pops up
This error occurs because, in React, elements must wrapped in a single parent
element. To fix this error, we can use a div as a wrapper for all the elements or use a
JSX fragment.
import "./styles.css";
Now the errors disappear and when we inspect the elements using browser tools, we
can see something like this;
Components
React is a component-based framework. A component is a function that returns React
elements. Components make up the UI of any React Application. A component can be
as small as a button or as big as a Navbar or Main content.
The first step to creating interactive user interfaces in React is to create components
since they are the building blocks of any React application. Components can be
created as standalone or inside other components. For example, in the App.js file, we
can add more components to it.
To create a standalone file, you need to create a new file in the src directory. When
naming components, ensure you use PascalCasing.
Create a new file named Menu.js . In the new component, let’s define the structure and
what it should display.
To render the Menu component as part of our UI, we need to render it as <Menu/> .
import "./styles.css";
import Menu from "./Menu";
export default function App() {
return (
<div className="App">
<h1>JOT RESTAURANT</h1>
<Menu />
</div>
);
}
The good thing about React is that, since it uses a virtual DOM,(a lightweight
in-memory representation of the real DOM) every time you make changes to your code,
the UI updates quickly without any page reload
Styling in React
You have probably seen the import "./styles.css"; import at the top of the App.js
file. This is responsible for importing all the CSS styles to be applied to the App
component elements.
React also allows us to add inline styles just as we would in HTML. However, the way
we do it in React is a bit different. Instead of strings, React expects the styles to be
contained in an object for the style attribute, with the CSS properties written in
camelCase. Here’s an example:
const styles = {
color: 'blue',
fontSize: '20px',
marginTop: '10px'
};
function MyComponent() {
return <div style={styles}>This is a styled text!</div>;
}
Notice how font-size becomes fontSize, and values are written as strings or
numbers where appropriate.
import "./styles.css";
const styles = {
color: "blue",
fontSize: "20px",
marginTop: "10px",
};
<div className="App">
<h2 style={styles}>JOT RESTAURANT</h2>
</div>
);
}
These styles will be added to the h2 tag and you will see that the heading has a blue
color
Props
You know how functions in JavaScript have arguments, and React components have
props. Props allow us to pass data from one component to another, typically from a
parent component to a child component.
In React, data can only be passed from parent to child components, not the other way
around, for example, we have a Menu and an App component, and since the App is the
parent component, we can only pass data downwards to its children.
Props are also read-only and shouldn’t be modified within a component. If a child
component needs to communicate changes or pass data back up to the parent, it can
do so using callback functions passed as props.
In the Menu component we we want to add a few dishes, update like this:
// menu.js
import React from "react";
Props (properties) allow us to pass data from parent to child components. We can use
props to pass data therefore making components more reusable and dynamic.
Create a new component called Menu . Inside this file, we will create an instance of
one burger, ie one item.
export default function Burger(props) {
return (
<div>
<div className="burger-item">
<h3>Beef Burger</h3>
<p>A classic beef burger with all the trimmings.</p>
</div>
</div>
);
}
You can see we have added the props in the function definition. Now rather than
hardcoding the name of the burger and the description, we will simply use props.name
and props.descriprtion
Now in the Menu component, we need to pass as many Burger instances as there are
burgers, so if we have 5 burgers in the menu, we will pass 5 Burger component
instances like this:
Let's start by adding one instance of the Burger component. First import the Burger
component at the top of the Menu.js file.
// menu.js
import Burger from "./Burger";
export default function Menu() {
return (
<div className="menu-container">
<Burger />
{/* the rest of the code */}
</div>
);
};
As you can see the first item is empty, that's because even though we have injected an
instance of the Burger component, we haven't defined the values, the Burger
component expects a name and a description.
Now we don't need the hard-coded data, since we have a reusable component. let's'
replace the rest of the data
Destructuring Props
When we define props as we have done above, we have no idea of what the props
object contains. Luckily with destructuring, we can destructure the properties {name,
description} and then rather than referencing props.name or props.description, we
do something like this;
List Items
If we were getting a large amount of data from an API or database, it would take us all
day to directly add the burger components in the JSX. To improve reusability and
maintainability, the best approach would be to define an array of burgers, and then
iterate over the array and create a component for each burger.
Create an array named burgers and add all the burger names. The array should be
defined at the top level, outside the function.
const burgers = [
{ name: "Beef Burger" },
{ name: "Cheeseburger" },
{ name: "Bacon Burger" },
{ name: "Veggie Burger" },
{ name: "Double Patty Burger" },
{ name: "Spicy Jalapeño Burger" },
{ name: "BBQ Burger" },
{ name: "Mushroom Swiss Burger" },
{ name: "Chicken Burger" },
{ name: "Fish Burger" },
{ name: "Impossible Burger" },
];
Keeping the array outside the component ensures the data is only created once when
the module is loaded. It is also good for performance since it can lead to unnecessary
performance overhead especially if the dataset is large., if we keep it inside the
component, it means that it will be rendered every time the component mounts.
Keeping the data outside the component also prevents redundant initializations since
the data is static.
The burgerList array will now contain an array of HTML strings for each burger. The
output will conain an array of HTML strings for each burger.
[
'<div><h3>Beef Burger</h3> </div>',
'<div><h3>Cheeseburger</h3> </div>',
'<div><h3>Bac Burger</h3> </div>'
]
Luckily react does a good job of unpacking arrays, So for example, if we injected this
data in you our JsX syntax like this:
{ [
'<div><h3>Beef Burger</h3> </div>',
'<div><h3>Cheeseburger</h3> </div>',
'<div><h3>Bac Burger</h3> </div>'
]}
const burgers = [
{
name: "Beef Burger",
description: "A classic beef burger with all the trimmings.",
},
{
name: "Cheeseburger",
description: "Juicy cheeseburger with melted cheddar cheese.",
},
{
name: "Bacon Burger",
description: "Delicious bacon burger with crispy bacon strips.",
},
{
name: "Veggie Burger",
description: "A hearty veggie burger with fresh ingredients.",
},
{
name: "Double Patty Burger",
description: "A massive burger with two juicy patties.",
},
{
name: "Spicy Jalapeño Burger",
description: "A spicy burger with jalapeños and pepper jack
cheese.",
},
];
Since the map() method must return something, in this case we want to create a
Burger component for each of the items in the burgers array and then pass the name
and description. Inside the menu-container div, call burgers.map and return a Burger
component for each element.
const burgers = [
{
name: "Beef Burger",
description: "A classic beef burger with all the trimmings.",
},
{
name: "Cheeseburger",
description: "Juicy cheeseburger with melted cheddar cheese.",
},
{
name: "Bacon Burger",
description: "Delicious bacon burger with crispy bacon strips.",
},
{
name: "Veggie Burger",
description: "A hearty veggie burger with fresh ingredients.",
},
{
name: "Double Patty Burger",
description: "A massive burger with two juicy patties.",
},
{
name: "Spicy Jalapeño Burger",
description: "A spicy burger with jalapeños and pepper jack
cheese.",
},
];
Once you update this, we can see an error that looks like this:
This error occurs because react needs each item in a list to have a unique key. To
resolve the error, we need to add a key to each element. Since the index is unique, let's
add it as the key. Although using the index as a key is not recommended because it can
lead to issues especially if any of the list items is removed or shifted in position you
might want to generate a unique key for each burger.
<div className="menu-container">
{burgers.map((burger,index) => (
<Burger key = {index}name={burger.name}
description={burger.description} />
))}
</div>
Conditional Rendering
Conditional rendering lets you render data based on certain conditions, for example,
suppose we wanted to render certain burgers only if they are available or spicy, let's add
additional properties to each burger namely is_available(boolean) and
isSpicy(boolean).
const burgers = [
{ name: "Beef Burger", description: "A classic beef burger with all
the trimmings.", available: true, isSpicy: false },
{ name: "Cheeseburger", description: "Juicy cheeseburger with
melted cheddar cheese.", available: true, isSpicy: false },
{ name: "Bacon Burger", description: "Delicious bacon burger with
crispy bacon strips.", available: false, isSpicy: false },
{ name: "Veggie Burger", description: "A hearty veggie burger with
fresh ingredients.", available: true, isSpicy: false },
{ name: "Double Patty Burger", description: "A massive burger with
two juicy patties.", available: true, isSpicy: false },
{ name: "Spicy Jalapeño Burger", description: "A spicy burger with
jalapeños and pepper jack cheese.", available: true, isSpicy: true }
];
Now we can conditionally render items based on these properties. This time, we will use
the filter method to render only the burgers that are spicy.
const availableBurgers = burgers.filter((burger) =>
burger.available);
In the code above , .filter(burger => burger.isSpicy) ensures that only burgers
where available: true are passed to the .map() function for rendering.
Let’s add the spicy Badge based on the isSpicy component within the burger
component.
Lastly, update the map method in the Menu component to use the available array rather
than the burgers array.
Even though JSX looks similar to HTML markup, there are some key differences you
will encounter when working with different elements. For example, let’s look at the input
and image elements.
<>
<img src=" " alt="A cute brown cat on white snow" />
<input type="text" placeholder="Type something..." />
</>
JSX Tags must be Closed
Both <img> and <input> are examples of self-closing tags. In HTML, it is okay to leave
self-closing tags open e.g (<img> ), however in JSX, you must explicitly close them by
adding a slash (/) before the closing >.
If you don't close these elements, you will get an error like this:
// Incorrect:
<img>
// Correct:
<img />
When you need to respond to an event on a button, you typically pass the function as
shown below for an onclick event.
In HTML, onclick is written in all lowercase. When a user clicks the button, the
handleClick function will be called.
However, in JSX, attributes that are Multi-word or part of the JavaScript language must
be written in camelCase. So the equivalent JSX will look like this:
function handleClick() {
alert("Hello");
}
In the code above, onClick is written in camelCase instead of onclick, and the function
handleClick is wrapped in curly braces to indicate that it is a JavaScript expression.
You might also have noticed that the function handleClick has not been invoked when
passed to the onClick attribute. This is because when the component renders, we don't
want to invoke the function immediately. In JSX, when handling event handlers, the
function should be passed as a reference without parentheses to avoid immediate
invocation on component mount.
What if you need to pass arguments to the function? In this case, you use an
arrow function which will call the handler with the desired arguments.
function handleClick(message) {
alert(message);
}
Conditionals in JSX
In JSX, conditional statements like if, for, switch, etc. are not allowed directly inside JSX
markup. If you need to perform conditional rendering, you can use ternary operators or
logical operators to conditionally render based on certain conditions.
// Incorrect:
if (isLoggedIn) {
return <h1>Welcome</h1>;
}
We will start with a simple counter example. The purpose of this counter is to increment
and decrement numbers when a button is clicked.
Create a new React application and in the App.js file, add the code below.
import "./styles.css";
import { useState } from "react";
export default function App() {
const [count, setCount] = useState(0);
return (
<div className="counter">
<button>-</button>
<span className="counter-number">{count}</span>
<button>+</button>
</div>
);
}
In React, state is used to manage dynamic content. To create a state variable, we use
the useState function. Whose syntax looks like this:
Where value is the current state, setValue is the function used to update the state,
and initialValue is the initial value of the state. The initial value can be empty, an array,
an object, or a string.
In our example, count is the current value of the state, and its initial value is 0.
setCount is the function used to update the state.
To update the counter, we need to add onClick event handlers to the buttons. The left
button will call a function to decrease the counter, while the right button will call a
function to increase the counter by 1.
To update the new state when a button is clicked, you can do so directly by calling the
setter function as follows:
setValue(value)
Let's update the state directly within our button using the setCount function within the
onClick event handler.
<div className="counter">
<button onClick={() => setCount(count - 1)}>-</button>
<span className="counter-number">{count}</span>
<button onClick={() => setCount(count + 1)}>+</button>
</div>
When you click any of the buttons, the counter will change. Under the hood, when the
state changes, it causes the component to re-render. Even though you don't see the
page refresh, React does a good job of updating only the parts of the DOM that need to
change.
In a traditional HTML form, data is typically collected from the input fields after the user
clicks the submit button. However, working with forms in React is a bit different and
slightly more complex. In React, every change in the input data must be captured and
maintained in the component's state.
By the time the user clicks the submit button, your application already has the input data
stored in its state.
● Immediate feedback: Since the state handles the submitted data, validation can
be done immediately before the user even submits the form.
In this traditional HTML form, we have the value “John,” which has been hardcoded.
However, in the React context, inputs are controlled elements, meaning that their
values are managed by the state. Therefore, we will bind the input value to a state
variable and handle changes to the value through state.
Let’s create a simple Login form with username and password fields in the App.js file.
import "./styles.css";
Once we bind the value to the state, we can see that the values shown on the input
fields are from the state.
The next step is to update the state when the input value changes. This is done by
adding the onChange event handler which listens for changes to the input field. As the
user types in the input, the event is triggered and the state is updated by the setter
function.
<input
type="password"
id="password"
name="password"
value={password}
placeholder="password"
/>
It’s recommended to set the initial value of the state for an input field to an empty string,
so let's do that.
Now the input fields are controlled by the state, and we are in a position to submit form
data. Let's do that. Add an onClick event handler to the submit button.
Create the submitData function and log the form data to the console.
function submitData(e) {
e.preventDefault();
// send data to server
💡In React, it's important to understand that state updates are asynchronous
and are typically batched together for performance optimization.
return (
<>
<button onClick={handleOpen}>Open Modal</button>
<div>
{isOpen && (
<div className={styles.overlay}>
<div className={styles.modal}>
<h2 className={styles.title}>Simple Modal</h2>
<p className={styles.content}>
This is a simple modal component </p>
<button onClick={closeModal}
className={styles.closeButton}>
Close Modal
</button>
</div>
</div>
)}
</div>
</>
);
}
In this code, we have a state that controls the opening and closing of a modal. When
isOpen is true, the modal is shown; if it is false, the modal is not displayed.
However, we have a problem: we want the button for opening the modal to reside in the
App.js component.
The App component cannot change the state of the modal since it has no access to the
state. In such a case, we have to lift the state from the Modal component and put it in
the App component.
This will allow us to add an Onclick event which will trigger a state change.
Let's start by moving the isOpen state and the functions that control the modal to the
App component.
function App() {
const [isOpen, setIsOpen] = useState(false);
const handleOpen = () => {
setIsOpen(true);
};
return (
<>
<button >Open Modal</button>
<Modal isOpen={isOpen} closeModal={closeModal} />
</>
);
}
The next step is to modify the Modal component so that it receives the state (isOpen)
and the closeModal function from the App component as props.
return (
<>
{/* <button onClick={props.handleOpen}>Open Modal</button> */}
<div>
{isOpen && (
<div className={styles.overlay}>
<div className={styles.modal}>
<h2 className={styles.title}>Simple Modal</h2>
<p className={styles.content}>
This is a simple modal component.
</p>
<button onClick={closeModal}
className={styles.closeButton}>
Close Modal
</button>
</div>
</div>
)}
</div>
</>
);
}
Lastly, attach an event listener to the open Modal function so that it will be responsible
for opening the modal.
● API requests
● Local storage
● Event listeners
● Subscriptions such as web sockets, e.t. c
API Requests
When you need to fetch data from an API in React, it creates a side effect since it
involves asynchronous operations. Since React components render on mount, an
asynchronous operation may not be completed in time before the component's initial
render. In such cases, we use the useEffect hook to perform API interactions.
Suppose you need to fetch data from an API, such as a placeholder that returns some
mock data. Let’s create a useEffect for that. In your App.js file, start by importing the
useEffect hook."
Next, define it
useEffect(()=>{
So for example in our case, we need to do a fetch request, let's do that inside the
useEffect hook.
function App() {
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/todos/1')
.then((res) => res.json())
.then((data) => {
console.log(data);
});
});
Now , everytime the app renders, the data will be fetched and logged to the console.
React offers another argument to the useEffect hook, which is the dependency array.
The dependency array determines what causes the useEffect to run. If you don’t want
the useEffect to run on every re-render, you can specify the dependency array.
For example, if we want the useEffect to run on component mount, we will specify an
empty dependency array, as shown below
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/todos/1')
.then((res) => res.json())
.then((data) => {
console.log(data);
});
},[]);
If you want the use Effect to run when something like state changes, you will add the
state to the dependency array,
For example, if we have a user state and we want it to control when the useEffect runs,
we would have something like this:
function App() {
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/todos/1')
.then((res) => res.json())
.then((data) => {
console.log(data);
});
},[user]);
Local Storage
Reading and writing to local storage is a side effect and should be handled in a similar
manner using the useEffect hook.
Consider this example where we have a simple note-taking app where a user adds
notes, and the notes are then displayed on the page
.
function App() {
const[note,setNote]=useState("");
const[notes,setNotes]=useState([]);
console.log(notes);
return (
<>
<input type="text" value={note}
onChange={(e)=>setNote(e.target.value)}/>
<button onClick={()=>setNotes([...notes,note])}>Add
Note</button>
{notes? notes.map((note,i)=>{
return <div key={i}>{note}</div>
}):null}
</>
);
}
When a user refreshes the app, all the notes will disappear. To ensure that all the notes
are displayed even after a refresh, we will store the notes in local storage.
Add a useEffect hook to save the current notes to local storage whenever the note
state changes. In this case, our dependency array will be note. This means that every
time a user adds a new note, the note will be saved to local storage.
useEffect(()=>{
localStorage.setItem("notes",JSON.stringify(notes));
},[notes])
Then we need to set the initial state of the notes to be the notes from local storage.
const[notes,setNotes]=useState(localStorage.getItem("notes")?
JSON.parse(localStorage.getItem("notes")):[]);
Here we are using a ternary operator which will first check if the item notes exists in
local storage and if it does, the array will be used as the initial value, if it doesnt exist,
the initial state will be an empty array.
function App() {
const[note,setNote]=useState("");
const[notes,setNotes]=useState(localStorage.getItem("notes")?
JSON.parse(localStorage.getItem("notes")):[]);
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/todos/1')
.then((res) => res.json())
.then((data) => {
console.log(data);
});
},[]);
useEffect(()=>{
localStorage.setItem("notes",JSON.stringify(notes));
},[notes])
function saveNote() {
if (note.trim()) {
setNotes((prevNotes) => [...prevNotes, note]);
setNote("");
}
}
return (
<>
{notes? notes.map((note,i)=>{
return <div key={i}>{note}</div>
}):null}
</>
);
}
Conclusion
Congratulations! You've just completed an introductory journey into the world of React.
Let's recap what we've learned:
As you continue your React journey, practice is key. Try building small projects that
incorporate these concepts, and don't be afraid to explore the React documentation for
more in-depth information.