Mastering React: A Beginner’s Guide with Detailed Examples

ElAmir Mansour
27 min readMay 20, 2024

--

Welcome to “Mastering React: A Beginner’s Guide with Detailed Examples”! If you’re new to the world of web development or looking to expand your skill set, React is an excellent library to learn. Developed and maintained by Facebook, React is a powerful JavaScript library for building dynamic and interactive user interfaces. Its component-based architecture, efficient rendering, and unidirectional data flow make it a popular choice for developers around the world.

In this comprehensive guide, we will walk you through the essentials of React, from setting up your environment to building complex applications. Each section will include detailed explanations and complete examples to help you understand and apply the concepts effectively. Whether you’re a complete beginner or have some experience with JavaScript, this guide will provide you with the knowledge and confidence to start building your own React applications.

Let’s embark on this exciting journey into the world of React!

Understanding the DOM and Responsiveness in JavaScript

What is the DOM?

The Document Object Model (DOM) is a programming interface for web documents. It represents the structure of a document as a tree of objects, where each node corresponds to a part of the document (e.g., an element, attribute, or text). The DOM allows programming languages like JavaScript to interact with and manipulate the content, structure, and style of a webpage.

Key points about the DOM:

  • Tree Structure: The DOM is structured as a tree with a root node (document), branches (elements like <div>, <p>), and leaves (text, attributes).
  • Manipulation: Using JavaScript, you can add, remove, or modify elements and their content dynamically.
  • Event Handling: The DOM supports event handling, allowing you to respond to user actions such as clicks, input changes, and more.

Example: Basic DOM Manipulation

Let’s create a simple example to illustrate DOM manipulation. We’ll add a new paragraph to a webpage when a button is clicked.

HTML:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DOM Manipulation Example</title>
</head>
<body>
<div id="content">
<h1>Welcome to the DOM Example</h1>
<button id="addParagraphBtn">Add Paragraph</button>
</div>
<script src="script.js"></script>
</body>
</html>

JavaScript (script.js) :

document.getElementById('addParagraphBtn').addEventListener('click', function() {
// Create a new paragraph element
const newParagraph = document.createElement('p');
// Set the text content of the new paragraph
newParagraph.textContent = 'This is a new paragraph added to the DOM!';
// Append the new paragraph to the content div
document.getElementById('content').appendChild(newParagraph);
});

In this example, clicking the “Add Paragraph” button triggers the creation and insertion of a new paragraph into the DOM.

What is Responsiveness in JavaScript?

Responsiveness refers to the ability of a webpage to adapt and respond to different devices, screen sizes, and user interactions. In the context of JavaScript, it means writing code that dynamically adjusts the layout and functionality of a webpage to provide an optimal user experience across various devices.

Techniques for Responsive JavaScript

  1. Media Queries: Although typically used in CSS, media queries can be combined with JavaScript to apply different styles or functionalities based on the viewport size.
  2. Event Listeners: JavaScript can listen for various events (like resizing the window) and adjust the layout or content accordingly.
  3. Flexbox and Grid Layouts: Utilizing modern CSS layouts in conjunction with JavaScript can help create flexible and adaptive designs.

Example: Responsive Design with JavaScript

Let’s create a responsive layout that changes the background color of the page based on the window size.

HTML:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Responsive JavaScript Example</title>
<style>
body {
transition: background-color 0.5s;
}
</style>
</head>
<body>
<h1>Resize the window to see the effect!</h1>
<script src="responsive.js"></script>
</body>
</html>

JavaScript (responsive.js):

function changeBackgroundColor() {
const width = window.innerWidth;
if (width < 600) {
document.body.style.backgroundColor = 'lightblue';
} else if (width < 900) {
document.body.style.backgroundColor = 'lightgreen';
} else {
document.body.style.backgroundColor = 'lightcoral';
}
}

// Initial call to set the background color based on the current window size
changeBackgroundColor();

// Change the background color when the window is resized
window.addEventListener('resize', changeBackgroundColor);

In this example, the background color of the page changes dynamically as the window is resized, demonstrating how JavaScript can be used to enhance responsiveness.

Note: Check you Node version.

If you don’t have installed yet , install it , if you already got it skip the next part.

Installing Node.js

What is Node.js?

Node.js is a runtime environment that allows you to execute JavaScript code outside of a web browser. It’s built on Chrome’s V8 JavaScript engine and is used for server-side development. Node.js is essential for working with React, as it enables you to run various tools and build processes needed for React development, such as create-react-app, a popular tool for setting up React projects.

Steps to Install Node.js

Download Node.js Installer:

  • Visit the official Node.js website.
  • You will see two versions: LTS (Long Term Support) and the latest current version. It’s recommended to download the LTS version for stability.

Run the Installer:

  • Open the downloaded installer.
  • Follow the installation prompts. The default settings are typically sufficient.
  • The installer will also include npm (Node Package Manager), which is essential for managing JavaScript packages.

Verify the Installation:

  • Open a command prompt or terminal window.
  • Type node -v and press Enter. This command will display the installed version of Node.js.
  • Type npm -v and press Enter to verify the installation of npm.

Ways to Create React Apps

There are several methods to create a React application, each offering different features and optimizations. Here, we’ll discuss three popular approaches: using create-react-app, Vite, and Next.js.

1. Create React App

Create React App (CRA) is a popular and straightforward way to set up a React project with a single command. It provides a modern build setup with no configuration.

Steps to Create a React App with CRA

  1. Install Create React App:
npx create-react-app my-app

2.Navigate to Your Project Directory:

cd my-app

3.Start the Development Server:

npm start

This method is excellent for beginners as it abstracts away much of the setup process, allowing you to focus on coding your application.

2. Vite ( We will work with vite in this article)

Vite is a build tool that aims to provide a faster and leaner development experience for modern web projects. It offers a much faster development server start time and HMR (Hot Module Replacement).

Steps to Create a React App with Vite

  1. Create a New Project:
npm create vite@latest my-vite-app -- --template react
Make sure to choose react and Typescript

2.Navigate to Your Project Directory:

cd my-vite-app

3.Install Dependencies:

npm install 

4.Start the Development Server:

npm run dev

Vite is particularly useful for larger projects and those needing faster development iteration due to its optimized build process.

3. Next.js

Next.js is a powerful React framework that enables functionalities like server-side rendering and generating static websites for React-based web applications.

Steps to Create a React App with Next.js

  1. Create a New Project:
npx create-next-app my-next-app

2.Navigate to Your Project Directory:

cd my-next-app

3.Start the Development Server:

npm run dev

Next.js is ideal for building production-ready applications with features like routing, server-side rendering, and static site generation out of the box.

Comparing the Methods

Relating These Methods to React Development

Each of these methods allows you to quickly set up and start developing React applications, but they cater to different needs:

  • Create React App: Best for beginners and those looking to quickly get started with a standard React setup.
  • Vite: Ideal for developers who need a faster development environment and optimized builds.
  • Next.js: Perfect for building advanced, production-ready applications with features like server-side rendering and static site generation.

By understanding these different approaches, you can choose the right tool for your project and leverage the strengths of each to build efficient and effective React applications.

Setting Up a React Project with Vite and VS Code

note(some steps could be skipped if you already done it )

Step-by-Step Guide to Create a React Project Named react-project Using Vite

1. Install Node.js

Ensure Node.js is installed on your system. You can verify the installation by running the following commands in your terminal:

node -v 
npm -v

2. Create a New React Project with Vite

Open your terminal and run the following commands to create a new React project named react-project:

npm create vite@latest react-project -- --template react
  • This command uses Vite to create a new React project with the template specified for React.

3. Navigate to Your Project Directory

cd react-project

4. Install Dependencies

Inside the react-project directory, install the necessary dependencies:

npm install 
or
npm i

5. Open the Project in VS Code or any editor

Open Visual Studio Code and navigate to your project directory. You can do this from the terminal by running:

code .

This command opens the current directory in VS Code.

6. Start the Development Server

To start the development server, run the following command in your terminal within the project directory:

npm run dev

This will start the Vite development server, and you can view your React application by opening http://localhost:5173 in your web browser.

Understanding the Project Structure

Once your project is set up and running, it’s essential to understand the basic structure of a Vite-powered React project.

Project Structure Overview

react-project/
├── node_modules/
├── public/
│ ├── favicon.ico
│ └── index.html
├── src/
│ ├── assets/
│ ├── components/
│ ├── App.css
│ ├── App.jsx
│ ├── index.css
│ ├── main.jsx
├── .gitignore
├── index.html
├── package.json
├── README.md
├── vite.config.js
  • public/: Contains static files like index.html.
  • src/: Contains the React components, CSS files, and the main entry point for the React application.
  • node_modules/: Contains all the npm packages installed.
  • .gitignore: Specifies which files and directories should be ignored by Git.
  • package.json: Lists the project dependencies and scripts.
  • vite.config.js: Configuration file for Vite.

Creating a Function-Based HelloWorld Component in React with TypeScript and Vite

Now, let’s create a simple React component to understand how React components work within a Vite project.

1. Create a New Component

Inside the src/components/ directory, create a new file named HelloWorld.tsx, if you didn’t find Components folder , make one .

// src/components/HelloWorld.tsx

import React from 'react';
import './HelloWorld.css';

function HelloWorld() {
return (
<div className="hello-world">
<h1>Hello, World!</h1>
<p>Welcome to your first React component with Vite and TypeScript.</p>
</div>
);
}

export default HelloWorld;

In this component:

  • We define a function-based component named HelloWorld.
  • We directly return the JSX content of the component.
  • We include a simple HTML structure with a heading and a paragraph.

2. Add Some Styles

Create a corresponding CSS file HelloWorld.css in the same directory:

/* src/components/HelloWorld.css */

.hello-world {
text-align: center;
margin-top: 50px;
}

.hello-world h1 {
color: #61dafb;
}

.hello-world p {
color: #282c34;
}

3. Use the Component in Your Application

Open App.tsx and import the HelloWorld component:

// src/App.tsx

import React from 'react';
import HelloWorld from './components/HelloWorld';

function App() {
return (
<div>
<h1>React App</h1>
<HelloWorld />
</div>
);
}

export default App;

In this component:

  • We import the HelloWorld component.
  • We render the HelloWorld component inside the App component.

NOTE: IF YOU Find you fiels full of erros here how to solve it :

updating the tsconfig.json from "moduleResolution": "bundler" to "moduleResolution": "node" resolves this

Run Your Application

With the development server running, open your browser and navigate to http://localhost:3000 to see your new HelloWorld component in action.

Conclusion

By setting up a React project with Vite and TypeScript and creating your first component, you’ve taken the initial steps toward building modern, type-safe, and efficient web applications. TypeScript provides additional benefits like static typing, which helps catch errors early in the development process.

Creating a React Component with Dynamic Content in JSX

Inside the src/components/ directory, create a new file named HelloWorld.tsx:

// src/components/HelloWorld.tsx

import React from 'react';

interface HelloWorldProps {
greeting: string;
}

function HelloWorld({ greeting }: HelloWorldProps) {
return (
<div>
<h1>{greeting}, World!</h1>
<p>Welcome to your first React component with Vite and TypeScript.</p>
</div>
);
}

export default HelloWorld;

In this component:

  • We define a function-based component named HelloWorld.
  • It accepts props of type HelloWorldProps, which includes a greeting property.
  • Inside the component, we interpolate the greeting prop to dynamically generate the greeting message.

2. Using the Component

Now, let’s use the HelloWorld component in another component.

Create a new file named App.tsx in the src/ directory:

// src/App.tsx

import React from 'react';
import HelloWorld from './components/HelloWorld';

function App() {
return (
<div>
<h1>React App</h1>
<HelloWorld greeting="Hello" />
<HelloWorld greeting="Bonjour" />
<HelloWorld greeting="Hola" />
</div>
);
}

export default App;

In this component:

  • We import the HelloWorld component.
  • We render the HelloWorld component multiple times with different greeting messages passed as props.

3. Running the Application

With the development server running (npm run dev), open your browser and navigate to http://localhost:3000 to see your application.

Deep Dive into the Code

In the HelloWorld component, we dynamically generate the greeting message based on the greeting prop passed to the component. This allows us to reuse the HelloWorld component with different greetings throughout the application.

Virtual DOM

How the Virtual DOM Works in Our HelloWorld Example

Initial Rendering:

  1. Component Creation: When the HelloWorld component is first rendered, React creates a Virtual DOM representation of the component's UI based on the JSX code provided.
  2. Virtual DOM Tree: This Virtual DOM tree includes elements like <div>, <h1>, and <p>, representing the structure of the component.

Updates:

  1. Prop Change: Let’s say the greeting prop of the HelloWorld component changes from "Hello" to "Bonjour".
  2. Re-rendering: React re-renders the HelloWorld component with the new prop value.
  3. New Virtual DOM: React generates a new Virtual DOM representation of the updated component based on the new prop value.

Diffing and Reconciliation:

  1. Diffing: React compares the new Virtual DOM with the previous one to identify the differences between them.
  2. Identifying Changes: In this case, React detects that the text content of the <h1> element has changed from "Hello, World!" to "Bonjour, World!".
  3. Minimal Updates: React calculates the most efficient way to update the real DOM to reflect these changes. Instead of re-rendering the entire component, React only updates the text content of the <h1> element.

Updating the Real DOM:

  1. Efficient DOM Update: React applies the necessary changes to the real DOM, updating only the specific parts that have changed. In this case, it updates the text content of the <h1> element to display the new greeting message.

Result:

  • The user sees the updated UI with the new greeting message ("Bonjour, World!") without experiencing any noticeable delays or flickering.

Benefits of the Virtual DOM in Our Example:

  1. Performance: React’s use of the Virtual DOM minimizes the number of DOM manipulations needed during updates, resulting in better performance.
  2. Efficiency: By comparing and updating only the parts of the UI that have changed, React ensures that updates are processed efficiently, even in complex UIs.
  3. Simplified Development: Developers can focus on building UI components without worrying about the underlying optimization of DOM updates. React handles these optimizations transparently.

Conclusion:

In our HelloWorld example, the Virtual DOM enables React to efficiently update the UI in response to changes in component props or state. By abstracting and optimizing the manipulation of the real DOM, React provides a smoother and more responsive user experience while simplifying the development process for developers.

Conditional Rendering in JSX

In JSX, you can use JavaScript expressions inside curly braces {}. This allows you to conditionally render elements based on certain conditions.

Basic Example

Let’s start with a simpler example. Suppose we want to render a message only if a certain condition is true. We can use a boolean variable to achieve this.

Example: Conditional Rendering with a Boolean Variable:

import React from 'react';

const SimpleComponent = () => {
const showMessage = true;

return (
<div>
<h1>Hello, World!</h1>
{showMessage && <p>This is a conditional message.</p>}
</div>
);
};

export default SimpleComponent;

In this example:

  • The <p> element is rendered only if showMessage is true.

Detailed Example: List with Conditional Dividers

Let’s create a simpler and more explicit example based on the previous ListGroupComponent scenario but focusing on conditional rendering.

Step-by-Step Guide

  1. Create a Simple List Component: This component will render a list of items and insert a divider between each item, except after the last item.
  2. Implement Conditional Rendering: We will use a simple condition to determine whether to render the divider.

Simple List Component:

import React from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';

const SimpleListComponent = ({ items }) => {
return (
<div className="container">
<ul className="list-group">
{items.map((item, index) => (
<React.Fragment key={index}>
<li className="list-group-item">{item}</li>
{index < items.length - 1 && <div className="divider"></div>}
</React.Fragment>
))}
</ul>
</div>
);
};

export default SimpleListComponent;

In this component:

  • We use map to iterate over the items array.
  • For each item, we render an <li> element with the class list-group-item.
  • We conditionally render a <div> with the class divider if the current item is not the last item in the list (index < items.length - 1).

Detailed Breakdown of Conditional Rendering

{index < items.length - 1 && <div className="divider"></div>}
  • index < items.length - 1: This condition checks if the current item is not the last item in the list.
  • && <div className="divider"></div>: If the condition is true, the <div> element with the class divider is rendered. If the condition is false, nothing is rendered.

What If Conditions Are Not Allowed?

If you encounter a situation where you cannot use inline conditional rendering, you can achieve the same effect by creating a separate function to handle the logic.

Example: Using a Function for Conditional Rendering

import React from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';

const SimpleListComponent = ({ items }) => {
const renderDivider = (index) => {
if (index < items.length - 1) {
return <div className="divider"></div>;
}
return null;
};

return (
<div className="container">
<ul className="list-group">
{items.map((item, index) => (
<React.Fragment key={index}>
<li className="list-group-item">{item}</li>
{renderDivider(index)}
</React.Fragment>
))}
</ul>
</div>
);
};

export default SimpleListComponent;

In this component:

  • We define a function renderDivider that takes the index of the current item.
  • The function checks if the current item is not the last one and returns a <div> element if true. Otherwise, it returns null.
  • We call renderDivider(index) inside the map function to conditionally render the divider.

Creating a ListGroupComponent with Bootstrap in React

Step-by-Step Guide

1. Install Bootstrap

If you haven’t already, install Bootstrap in your React project using npm:

npm install bootstrap

2. Create the ListGroupComponent

Create a new file named ListGroupComponent.jsx in the src/components/ directory:

// src/components/ListGroupComponent.jsx

import React from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';

function ListGroupComponent({ items }) {
return (
<ul className="list-group">
{items.map((item, index) => (
<li key={index} className="list-group-item">
{item}
</li>
))}
</ul>
);
}

export default ListGroupComponent;

In this component:

  • We import Bootstrap’s CSS file to style our list group.
  • We define a function-based component named ListGroupComponent.
  • It accepts a prop items, which is an array of items to display in the list group.
  • We use the Bootstrap class list-group to style the <ul> element as a list group.
  • Each item in the list is rendered as an <li> element with the class list-group-item.

3. Using the ListGroupComponent

Now, let’s use the ListGroupComponent in another component.

Create a new file named App.jsx in the src/ directory:

// src/App.jsx

import React from 'react';
import ListGroupComponent from './components/ListGroupComponent';

function App() {
const items = ['Item 1', 'Item 2', 'Item 3'];

return (
<div className="container">
<h1>React List Group Example</h1>
<ListGroupComponent items={items} />
</div>
);
}

export default App;

In this component:

  • We import the ListGroupComponent.
  • We define an array of items.
  • We render the ListGroupComponent and pass the items array as a prop.

4. Running the Application

Open your browser and navigate to http://localhost:5173 to see your application.

Make sure to update main.tsx:

import 'bootstrap/dist/css/bootstrap.css'

How to Download the ListGroupComponent

To download the ListGroupComponent and use it in another project, you can follow these steps:

  1. Navigate to the directory of your React project.
  2. Copy the ListGroupComponent.jsx file from the src/components/ directory.
  3. Paste the file into the components directory of your new React project.
  4. Install Bootstrap in the new project if you haven’t already:
npm install bootstrap

Import the ListGroupComponent in any component where you want to use it, and pass the items prop as needed.

In this example, we created a ListGroupComponent using Bootstrap in a React project. We demonstrated how to use it to display a list of items in a styled list group. Additionally, I provided steps on how to download and use the ListGroupComponent in another React project.

Understanding React Fragments

React Fragments allow you to group a list of children without adding extra nodes to the DOM. This can be useful when you need to return multiple elements from a component render method but don’t want to introduce unnecessary wrappers.

Why Use Fragments?

  1. Avoid Unnecessary Wrappers: Helps avoid adding unnecessary <div> tags or other elements just to wrap multiple elements.
  2. Improved Performance: Reduces the number of nodes in the DOM, which can improve performance.

How to Use React Fragments

React provides two ways to use fragments:

  1. Using the <React.Fragment> Element
  2. Using the Short Syntax (<> </>)

Example: Using Fragments in a ListGroupComponent

Let’s modify our ListGroupComponent example to use Fragments.

Step-by-Step Guide

1. Using <React.Fragment>

Modify the ListGroupComponent.jsx to include fragments:

// src/components/ListGroupComponent.jsx

import React from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';

function ListGroupComponent({ items }) {
return (
<ul className="list-group">
{items.map((item, index) => (
<React.Fragment key={index}>
<li className="list-group-item">{item}</li>
{index < items.length - 1 && <div className="divider"></div>}
</React.Fragment>
))}
</ul>
);
}

export default ListGroupComponent;

In this component:

  • We use <React.Fragment> to wrap the <li> and an optional <div> element (used here as a divider for demonstration).

2. Using the Short Syntax (<> </>)

You can simplify the fragment syntax using the short form:

// src/components/ListGroupComponent.jsx

import React from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';

function ListGroupComponent({ items }) {
return (
<ul className="list-group">
{items.map((item, index) => (
<>
<li key={index} className="list-group-item">{item}</li>
{index < items.length - 1 && <div className="divider"></div>}
</>
))}
</ul>
);
}

export default ListGroupComponent;

In this component:

  • We use the short syntax <> </> to wrap the elements, making the code cleaner.

Using the Component

The usage of ListGroupComponent remains the same as before:

// src/App.jsx

import React from 'react';
import ListGroupComponent from './components/ListGroupComponent';

function App() {
const items = ['Item 1', 'Item 2', 'Item 3'];

return (
<div className="container">
<h1>React List Group Example</h1>
<ListGroupComponent items={items} />
</div>
);
}

export default App;

Using React Fragments (<React.Fragment> or the short syntax <> </>) allows us to group multiple elements without adding extra nodes to the DOM. This makes our components cleaner and potentially more performant.

Why adding the ‘key’ Prop?

  1. Identifying Elements: React uses the key prop to uniquely identify each element in a list. This allows React to keep track of elements and their state between re-renders.
  2. Performance Optimization: By providing a unique key for each element, React can quickly determine which elements need to be updated, added, or removed. This minimizes the number of re-renders and updates, improving performance.
  3. Avoiding Bugs: Without unique keys, React may not correctly identify changes in the list, which can lead to unexpected bugs and rendering issues. For example, if you re-order or filter the list, React might not correctly update the elements without unique keys.

Example: Understanding the key Prop

In our ListGroupComponent, we use the key prop to ensure each list item is uniquely identified:

// src/components/ListGroupComponent.tsx

import React from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';

interface ListGroupComponentProps {
items: string[];
}

const ListGroupComponent: React.FC<ListGroupComponentProps> = ({ items }) => {
return (
<ul className="list-group">
{items.map((item, index) => (
<React.Fragment key={index}>
<li className="list-group-item">{item}</li>
{index < items.length - 1 && <div className="divider"></div>}
</React.Fragment>
))}
</ul>
);
};

export default ListGroupComponent;

In this component:

  • Each React.Fragment element within the map function receives a key prop. The key prop is set to index, which is the position of the item in the items array.

Important Considerations

  1. Unique Keys: The key prop should be unique among siblings. Using indices as keys (key={index}) is often discouraged, especially if the list can change (e.g., items are added, removed, or reordered). A more stable unique identifier should be used, such as a unique ID from the data.
  2. Why Not Index as Key?: Using the index of an item as the key can cause issues when the list is dynamic. If the list changes, the indices may change as well, causing React to re-render items unnecessarily. This can lead to performance issues and incorrect UI updates.

Improved Example Using Unique IDs

If our items had unique IDs, we would use them as keys:

// src/components/ListGroupComponent.tsx

import React from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';

interface Item {
id: number;
name: string;
}

interface ListGroupComponentProps {
items: Item[];
}

const ListGroupComponent: React.FC<ListGroupComponentProps> = ({ items }) => {
return (
<ul className="list-group">
{items.map((item) => (
<React.Fragment key={item.id}>
<li className="list-group-item">{item.name}</li>
{item.id < items.length - 1 && <div className="divider"></div>}
</React.Fragment>
))}
</ul>
);
};

export default ListGroupComponent;

In this improved example:

  • We assume each item has a unique id property.
  • We use item.id as the key prop, ensuring a stable and unique identifier for each element in the list.

Conclusion

The key prop is essential for list rendering in React. It helps React efficiently update and manage lists by uniquely identifying each element. This optimization is crucial for performance and correctness, especially when dealing with dynamic lists. Always strive to use stable and unique keys, avoiding indices when possible, to ensure smooth and accurate rendering of your React components.

Handling events in React is very similar to handling events in plain JavaScript. However, there are some differences that are important to understand. In React, event handling is done through camelCase syntax and you pass event handlers as functions, rather than strings.

Basic Event Handling

Let’s start with a simple example of handling a button click event.

Example 1: Button Click Event

import React from 'react';

const ButtonClickExample = () => {
const handleClick = () => {
alert('Button was clicked!');
};

return (
<button onClick={handleClick}>
Click Me
</button>
);
};

export default ButtonClickExample;

In this example:

  • We define a function handleClick that will be called when the button is clicked.
  • We use the onClick attribute to attach the event handler to the button.

Event Object

React’s event handling system provides a synthetic event, which is a cross-browser wrapper around the browser’s native event. This synthetic event has the same interface as the native event, including stopPropagation and preventDefault.

Example 2: Accessing the Event Object

import React from 'react';

const EventObjectExample = () => {
const handleClick = (event) => {
console.log('Event:', event);
console.log('Button was clicked!');
};

return (
<button onClick={handleClick}>
Click Me
</button>
);
};

export default EventObjectExample;

In this example:

  • The handleClick function takes an event parameter, which is the synthetic event.
  • We log the event object to the console to see its properties.

Note: you might have a line under event which is a “typescript” error , here is how to solve it .

import {MouseEvent} from 'react';

const EventObjectExample = () => {
const handleClick = (event : MouseEvent) => {
console.log('Event:', event);
console.log('Button was clicked!');
};

return (
<button onClick={handleClick}>
Click Me
</button>
);
};

export default EventObjectExample;

By importing MouseEvent from react and defining the event type , the error is now gone.

Handling Events with Parameters

If you need to pass additional parameters to your event handler, you can use an arrow function or bind the function.

Example 3: Passing Parameters with an Arrow Function

import React from 'react';
import {MouseEvent} from 'react';

const PassingParamsExample = () => {
const handleClick = (param, event) => {
console.log('Param:', param);
console.log('Event:', event: MouseEvent);
};

return (
<button onClick={(event) => handleClick('Hello', event)}>
Click Me
</button>
);
};

export default PassingParamsExample;

In this example:

  • We use an arrow function inside the onClick attribute to pass an additional parameter to the handleClick function.

Example 4: Passing Parameters with bind

import React from 'react';
import {MouseEvent} from 'react';

const PassingParamsExampleBind = () => {
const handleClick = (param, event) => {
console.log('Param:', param);
console.log('Event:', event);
};

return (
<button onClick={handleClick.bind(this, 'Hello')}>
Click Me
</button>
);
};

export default PassingParamsExampleBind;

In this example:

  • We use the bind method to pass an additional parameter to the handleClick function.

Common Event Types

React supports various event types, including mouse events, form events, keyboard events, and more. Here are some common examples:

Example 5: Mouse Events

import React from 'react';

const MouseEventExample = () => {
const handleMouseEnter = () => {
console.log('Mouse entered!');
};

const handleMouseLeave = () => {
console.log('Mouse left!');
};

return (
<div
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
style={{ width: '200px', height: '100px', backgroundColor: 'lightblue' }}
>
Hover over me!
</div>
);
};

export default MouseEventExample;

In this example:

  • We handle onMouseEnter and onMouseLeave events on a div element.

Example 6: Form Events

import React, { useState } from 'react';

const FormEventExample = () => {
const [value, setValue] = useState('');

const handleChange = (event) => {
setValue(event.target.value);
};

const handleSubmit = (event) => {
event.preventDefault();
alert('Form submitted: ' + value);
};

return (
<form onSubmit={handleSubmit}>
<label>
Name:
<input type="text" value={value} onChange={handleChange} />
</label>
<button type="submit">Submit</button>
</form>
);
};

export default FormEventExample;

In this example:

  • We handle onChange and onSubmit events for a form.
  • The handleChange function updates the state when the input value changes.
  • The handleSubmit function handles the form submission and prevents the default form submission behavior.

Example 7: Keyboard Events

import React from 'react';

const KeyboardEventExample = () => {
const handleKeyDown = (event) => {
if (event.key === 'Enter') {
alert('Enter key pressed!');
}
};

return (
<input type="text" onKeyDown={handleKeyDown} placeholder="Press Enter" />
);
};

export default KeyboardEventExample;

In this example:

  • We handle the onKeyDown event for an input field.
  • The handleKeyDown function checks if the Enter key was pressed and shows an alert.

Combining Multiple Event Handlers

You can combine multiple event handlers in a single component to handle different types of events.

Example 8: Combining Event Handlers

import React, { useState } from 'react';

const CombinedEventHandlersExample = () => {
const [text, setText] = useState('');
const [hover, setHover] = useState(false);

const handleChange = (event) => {
setText(event.target.value);
};

const handleMouseEnter = () => {
setHover(true);
};

const handleMouseLeave = () => {
setHover(false);
};

const handleSubmit = (event) => {
event.preventDefault();
alert('Form submitted: ' + text);
};

return (
<div>
<form onSubmit={handleSubmit}>
<label>
Name:
<input type="text" value={text} onChange={handleChange} />
</label>
<button type="submit">Submit</button>
</form>
<div
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
style={{
width: '200px',
height: '100px',
backgroundColor: hover ? 'lightgreen' : 'lightcoral',
marginTop: '20px'
}}
>
Hover over me!
</div>
</div>
);
};

export default CombinedEventHandlersExample;

In this example:

  • We handle form events (onChange, onSubmit) and mouse events (onMouseEnter, onMouseLeave) in a single component.
  • The background color of the div changes based on the hover state.

Conclusion

Event handling in React is straightforward and flexible, allowing you to handle a wide range of user interactions. By understanding the basic principles and exploring different types of events, you can create interactive and dynamic user interfaces. Remember to use unique event handlers and pass any necessary parameters using arrow functions or the bind method.

Managing state is a crucial concept in React. State represents dynamic data that changes over time and impacts what gets rendered on the screen. React provides several hooks to manage state in function components, with the most commonly used hook being useState.

Basic State Management with useState

The useState hook is used to add state to functional components. Let's start with a simple example.

Example 1: Counter Component

import React, { useState } from 'react';

const Counter = () => {
// Declare a state variable named "count" and a function "setCount" to update it
const [count, setCount] = useState(0);

return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
};

export default Counter;

In this example:

  • We use useState to declare a state variable count initialized to 0.
  • The setCount function updates the count state.
  • When the button is clicked, setCount increments the count state by 1.

Updating State

State updates are asynchronous and can be batched for performance improvements. Always use the updater function returned by useState to modify state.

Example 2: Input Field

import React, { useState } from 'react';

const InputField = () => {
// Declare a state variable named "inputValue" and a function "setInputValue" to update it
const [inputValue, setInputValue] = useState('');

const handleChange = (event) => {
setInputValue(event.target.value);
};

return (
<div>
<input type="text" value={inputValue} onChange={handleChange} />
<p>You typed: {inputValue}</p>
</div>
);
};

export default InputField;

In this example:

  • We use useState to declare a state variable inputValue initialized to an empty string.
  • The handleChange function updates inputValue with the current value of the input field.
  • The input element's value is controlled by inputValue.

Managing Complex State

Sometimes you need to manage more complex state, such as an object or array.

Example 3: Managing an Object

import React, { useState } from 'react';

const UserProfile = () => {
// Declare a state variable "user" with an object
const [user, setUser] = useState({ name: '', age: '' });

const handleNameChange = (event) => {
setUser({ ...user, name: event.target.value });
};

const handleAgeChange = (event) => {
setUser({ ...user, age: event.target.value });
};

return (
<div>
<input
type="text"
placeholder="Name"
value={user.name}
onChange={handleNameChange}
/>
<input
type="text"
placeholder="Age"
value={user.age}
onChange={handleAgeChange}
/>
<p>
Name: {user.name}, Age: {user.age}
</p>
</div>
);
};

export default UserProfile;

In this example:

  • We use useState to manage an object representing a user's profile.
  • We handle changes to the name and age properties by spreading the existing state and updating the specific property.

Example 4: Managing an Array

import React, { useState } from 'react';

const TodoList = () => {
// Declare a state variable "todos" initialized to an empty array
const [todos, setTodos] = useState([]);
const [inputValue, setInputValue] = useState('');

const addTodo = () => {
setTodos([...todos, inputValue]);
setInputValue('');
};

return (
<div>
<input
type="text"
value={inputValue}
onChange={(event) => setInputValue(event.target.value)}
/>
<button onClick={addTodo}>Add Todo</button>
<ul>
{todos.map((todo, index) => (
<li key={index}>{todo}</li>
))}
</ul>
</div>
);
};

export default TodoList;

In this example:

  • We use useState to manage an array of todos.
  • We handle adding new todos by spreading the existing array and adding the new todo.

Conditional State Updates

Sometimes you need to update the state conditionally.

Example 5: Conditional State Update

import React, { useState } from 'react';

const ConditionalCounter = () => {
const [count, setCount] = useState(0);

const incrementIfOdd = () => {
if (count % 2 !== 0) {
setCount(count + 1);
}
};

return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
<button onClick={incrementIfOdd}>Increment if odd</button>
</div>
);
};

export default ConditionalCounter;

In this example:

  • We conditionally update the count state only if it's odd.

Using Multiple State Variables

You can use multiple useState calls to manage different pieces of state within a single component.

Example 6: Multiple State Variables

import React, { useState } from 'react';

const MultiStateComponent = () => {
const [name, setName] = useState('');
const [age, setAge] = useState('');
const [city, setCity] = useState('');

return (
<div>
<input
type="text"
placeholder="Name"
value={name}
onChange={(event) => setName(event.target.value)}
/>
<input
type="text"
placeholder="Age"
value={age}
onChange={(event) => setAge(event.target.value)}
/>
<input
type="text"
placeholder="City"
value={city}
onChange={(event) => setCity(event.target.value)}
/>
<p>
Name: {name}, Age: {age}, City: {city}
</p>
</div>
);
};

export default MultiStateComponent;

In this example:

  • We use multiple useState calls to manage different pieces of state (name, age, city).

Conclusion

Managing state in React is a foundational concept that allows you to create interactive and dynamic components. By understanding and utilizing the useState hook, you can handle simple and complex state updates, manage arrays and objects, conditionally update state, and work with multiple state variables. These examples provide a solid basis for managing state effectively in your React applications.

Passing Via Props

Passing data via props is an essential concept in React, as it allows you to pass information from one component to another. Props (short for properties) are read-only and can be used to pass data, functions, or even other components from a parent component to its children.

Basic Example of Passing Props

Let’s start with a simple example where a parent component passes a message to a child component.

Example 1: Passing a Message

import React from 'react';

// Child component
const Message = ({ text }) => {
return <p>{text}</p>;
};

// Parent component
const App = () => {
const message = "Hello, World!";
return (
<div>
<Message text={message} />
</div>
);
};

export default App;

In this example:

  • The Message component is a child component that receives a text prop.
  • The App component is a parent component that defines the message variable and passes it to the Message component via the text prop.

Passing Multiple Props

You can pass multiple props to a child component.

Example 2: Passing Multiple Props

import React from 'react';

// Child component
const UserInfo = ({ name, age }) => {
return (
<div>
<p>Name: {name}</p>
<p>Age: {age}</p>
</div>
);
};

// Parent component
const App = () => {
const userName = "John Doe";
const userAge = 30;
return (
<div>
<UserInfo name={userName} age={userAge} />
</div>
);
};

export default App;

In this example:

  • The UserInfo component is a child component that receives name and age props.
  • The App component passes userName and userAge to the UserInfo component via the name and age props.

Passing Functions as Props

Props can also be used to pass functions from a parent component to a child component, allowing the child component to call functions defined in the parent component.

Example 3: Passing Functions

import React from 'react';

// Child component
const Button = ({ onClick, label }) => {
return <button onClick={onClick}>{label}</button>;
};

// Parent component
const App = () => {
const handleClick = () => {
alert('Button clicked!');
};

return (
<div>
<Button onClick={handleClick} label="Click Me" />
</div>
);
};

export default App;

In this example:

  • The Button component is a child component that receives an onClick function and a label prop.
  • The App component defines the handleClick function and passes it to the Button component via the onClick prop.

Passing Components as Props

You can also pass entire components as props to achieve higher levels of reusability.

Example 4: Passing Components

import React from 'react';

// Child component
const Container = ({ header, content }) => {
return (
<div>
<header>{header}</header>
<main>{content}</main>
</div>
);
};

// Parent component
const App = () => {
const Header = () => <h1>Welcome to My App</h1>;
const Content = () => <p>This is the main content of the app.</p>;

return (
<div>
<Container header={<Header />} content={<Content />} />
</div>
);
};

export default App;

In this example:

  • The Container component receives header and content props, which are entire components.
  • The App component defines the Header and Content components and passes them to the Container component via the header and content props.

Props Validation with TypeScript

When using TypeScript, you can define prop types using interfaces or type aliases to ensure that your components receive the correct types of props.

Example 5: Props Validation with TypeScript

import React from 'react';

// Define the props interface
interface UserInfoProps {
name: string;
age: number;
}

// Child component with props validation
const UserInfo: React.FC<UserInfoProps> = ({ name, age }) => {
return (
<div>
<p>Name: {name}</p>
<p>Age: {age}</p>
</div>
);
};

// Parent component
const App: React.FC = () => {
const userName = "John Doe";
const userAge = 30;
return (
<div>
<UserInfo name={userName} age={userAge} />
</div>
);
};

export default App;

In this example:

  • The UserInfoProps interface defines the expected props for the UserInfo component.
  • The UserInfo component uses React.FC<UserInfoProps> to specify the prop types, ensuring that it receives the correct props.

Conclusion

Passing data via props in React is a fundamental concept that allows you to create reusable and modular components. By understanding how to pass simple data, multiple props, functions, and even other components as props, you can build complex and interactive UIs. Additionally, using TypeScript for prop validation can help catch errors early and make your components more robust.

differences and similarities between props and state in React:

Similarities:

  • Both are JavaScript objects used to store information in React components.
  • Both can be accessed using dot notation (this.props in class components or directly in functional components, and this.state in class components).
  • Changes to both props and state can trigger re-renders of the component.
  • Both props and state can be passed down to child components.

Understanding the differences and similarities between props and state is essential for effective React development, as it helps in designing components and managing data flow within the application.

If you found this blog helpful or have any questions, feel free to reach out to me on social media:

--

--

ElAmir Mansour
ElAmir Mansour

Written by ElAmir Mansour

🚀 Software Engineer & iOS Developer | Scrum Master 🕹 | Crafting Code & Content | Coffee enthusiast ☕️ | Simplifying Complexity, One Line at a Time 💻