React JS

Introduction

Objectives

  1. Introduction to React
  2. Setting up the Development Environment
  3. Components and JSX
  4. Rendering Elements
  5. Props and State

1. Introduction to React

React is an open-source JavaScript library for building user interfaces.  It was created by Facebook (now Meta) and is widely used for building single-page applications (SPAs) and dynamic web apps

Analogie !

Think of React as a LEGO set for building UIs: you create small, reusable pieces (components) and snap them together to build something amazing.

Why Use React JS

Key Features & Benefits

&

Code Reusability

const UserCard = ({ user }) => {
  return (
    <div className="user-card">
      <img src={user.avatar} alt={user.name} className="avatar" />
      <div className="user-details">
        <h2>{user.name}</h2>
        <p>Email: {user.email}</p>
      </div>
    </div>
  );
};

Efficiency and Performance

Virtual DOM

Efficiently updates only necessary parts of the UI

Components

Everything in React is a component!

Modular building blocks for UI

Vibrant Community

  • Large developer community
  • Abundance of open-source libraries

Popularity

Widely adopted by major companies and developers worldwide

Real-World Example: Why React?

Imagine you're building a restaurant review app. Instead of writing HTML for every restaurant review, React allows you to create a Review Component, which you can reuse for multiple reviews. This makes development faster and more efficient.

2. Setting up the Development Environment:

What are bundlers ?

A bundler takes all your code and resource files, transforms and optimizes them, then bundles them into one or more files ready to be loaded into the browser.

Vite

Vite is a next-generation build tool for frontend development. It focuses on speed and efficiency by leveraging ES Module imports and server-side rendering (SSR) capabilities.

CRA

Create React App is the traditional way to create single-page React applications. It sets up a new React project with a pre-configured build setup using webpack and Babel.

SWC excels in performance and modern JavaScript/TypeScript support, making it ideal for projects that require fast compilation times and support for the latest ECMAScript features.

Babel, while slightly slower in compilation speed compared to SWC, offers unparalleled flexibility, extensive plugin support, and broad compatibility across different JavaScript environments and syntax versions.

SWC vs Babel

Compilers

Creating a new React project using Vite

npm create vite@latest 

Let’s create a React project using Vite. Open your terminal and run:

Understanding the project structure

Managing project dependencies with npm

Creating and using components in React

3. Components and JSX:

In React, a component is a reusable, self-contained piece of code that encapsulates the structure (HTML), behavior (JavaScript), and styling (CSS) of a part of the user interface.

There are two types:

  1. Class Components: ES6 classes that extend React.Component.
  2. Functional Components: Simple JS functions that return JSX.

React’s Component-Based Approach vs Traditional HTML, CSS, and JavaScript

Why React’s Approach is Better ?

  1. Encapsulation
  2. Reusability
  3. Maintainability
  4. Scalability

What is JSX ?

JSX (JavaScript XML) is a syntax extension for JavaScript that allows you to write HTML-like code directly in your JavaScript files.

Why use JSX?

  • Readability: JSX looks like HTML, making it easier to visualize the structure of your components.
  • Expressiveness: You can embed JavaScript expressions inside JSX using curly braces {}.
  • Encapsulation: JSX allows you to keep your UI logic and structure together in one place.

What is JSX ?

<div>
  	<h1>Hello, {fullName}!</h1>
	<p>Welcome to my React app.</p>
</div>
const fullName="Naruto UZUMAKI"

Components

Class Components

Class components are ES6 classes that extend the React.Component class. They can have state and lifecycle methods, making them more suitable for complex logic and interactions. 

Creating Class Components

import React from 'react';

class Header extends React.Component {
  render() {
    return <header>Welcome to My React App ! 🎉</header>;
  }
}

The Header component is a class component that returns a <header> element using JSX.

Creating Class Components

import React from 'react';

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 };
  }

  handleIncrement = () => {
    this.setState({ count: this.state.count + 1 });
  };

  render() {
    return (
      <div>
        <p>Count: {this.state.count}</p>
        <button onClick={this.handleIncrement}>Increment</button>
      </div>
    );
  }
}

Components

Functional Components

Functional components are JavaScript functions that return JSX (JavaScript XML) to describe what should be rendered on the screen. They are simpler and modern approach to building components. They are stateless, meaning they don't have internal state or lifecycle methods.

Components

Functional Components

However, with the introduction of React Hooks, functional components can now handle state and side effects effectively, reducing the need for class components in many cases.

Creating Functional Components

function Header() {
  return <header>Welcome to My React App ! 🎉</header>;
}

Creating Functional Components

import React from 'react';

const MyComponent = (props) => {
  return (
    <div>
      <h2>Hello, {props.name}!</h2>
      <p>{props.message}</p>
    </div>
  );
};

4. Props

In React, data is typically passed from a parent component to a child component through props. Props (short for "properties") are read-only and allow data to flow in one direction, from parent to child components.

Properties

// ParentComponent.js
import React from 'react';
import ChildComponent from './ChildComponent';

const ParentComponent = () => {
  const name = 'John Doe';
  return <ChildComponent name={name} />;
};
// ChildComponent.js
import React from 'react';

const ChildComponent = (props) => {
  return <p>Hello, {props.name}!</p>;
};

Props Destructuring: Cleaner Code

// ParentComponent.js
import React from 'react';

function UserCard({ name, age }) {
  return (
    <div>
      <h2>{name}</h2>
      <p>Age: {age}</p>
    </div>
  );
}
// ChildComponent.js
import React from 'react';

function Greeting(pops) {
  return <h1>Hello, {props.name}!</h1>;
}

function Greeting({ name }) {
  return <h1>Hello, {name}!</h1>;

Destructuring is a JavaScript feature that allows you to extract values from objects or arrays into variables. It makes your code cleaner and easier to read.

Exo: Color palette Gallery

Passing Functions as Props

// Parent Component
function App() {
  const handleClick = () => {
    alert('Button clicked in the parent component!');
  };

  return <Button onClick={handleClick} />;
}

// Child Component
function Button({ onClick }) {
  return <button onClick={onClick}>Click Me</button>;
}

Sometimes, you need to pass a function from a parent component to a child component to handle events or update the parent’s state. This is a common pattern in React.

PropTypes: Validating Props

npm install prop-types

PropTypes are a way to validate the types of props passed to a component. They help catch bugs by ensuring that the correct data types are used.

import PropTypes from 'prop-types';
function UserCard({ name, age }) {
  return (
    <div>
      <h2>{name}</h2>
      <p>Age: {age}</p>
    </div>
  );
}
UserCard.propTypes = { // Define PropTypes
  name: PropTypes.string.isRequired,
  age: PropTypes.number.isRequired,
};

PropTypes: Validating Props

Common PropTypes

  • PropTypes.string: The prop must be a string.

  • PropTypes.number: The prop must be a number.

  • PropTypes.bool: The prop must be a boolean.

  • PropTypes.func: The prop must be a function.

  • PropTypes.node: The prop must be a renderable value (e.g., string, number, element).

  • PropTypes.element: The prop must be a React element.

 

Children Props: Nesting Components

The children prop is a special prop that allows you to pass content between the opening and closing tags of a component. It’s like a placeholder for nested content.

function App() {
  return (
    <Card>
      <h2>Hello, World!</h2>
      <p>This is a card component.</p>
    </Card>
  );
}

// Child Component
function Card({ children }) {
  return <div style={styles.card}>{children}</div>;
}

5. States

State is a built-in React object that stores data or information about the component. It allows components to manage dynamic data and re-render when the state changes. Think of state as the memory of a component.

State in Class Components

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = { count: 0 }; // Initialize state
  }
  increment = () => {  // Method to increment count
    this.setState({ count: this.state.count + 1 });
  }; 
  decrement = () => {  // Method to decrement count
    this.setState({ count: this.state.count - 1 });
  };
  render() {
    return (
      <div>
        <p>Count: {this.state.count}</p>
        <button onClick={this.increment}>Increment</button>
        <button onClick={this.decrement}>Decrement</button>
      </div>
    );
  }
}
export default Counter;

In class components, state is initialized in the constructor and updated using the setState method.

setState callback

increment = () => {
  this.setState(
    { count: this.state.count + 1 },
    () => {
      console.log('State updated! New count:', this.state.count);
    }
  );
};

Sometimes, you need to perform an action after the state has been updated. You can pass a callback function as the second argument to setState.

State in Functional Components

function Greeting({ name }) {
  return <h1>Hello, {name}!</h1>;
}

Functional components are stateless, doesn’t use state. It only receives data via props and renders UI.

6. Hooks

React Hooks are special functions that were introduced to address some of the limitations of functional components and to provide a more cohesive way to handle state and side effects in React applications.

Benefits

  • Reusable Stateful Logic:
    With Hooks, you can extract and reuse stateful logic across multiple components using custom Hooks.

Benefits

Simplified Component Logic: Hooks allow you to write functional components without needing to convert them into class components just for state management.

Throw  Classes

Benefits

Improved Readability: Functional components using Hooks often have cleaner and more readable code.

Benefits

Popularity

Widely adopted by major companies and developers worldwide

7. State Hook

The useState hook is the simplest and most commonly used hook. It lets you manage data that can change in your component.

const [state, setState] = useState(initialState);
import React, { useState } from 'react';

export function Counter() {
  const [count, setCount] = useState(0);

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

Example 1: Counter

Exo : Add the decrement and reset buttons !

import React, { useState } from 'react';

function ToggleButton() {
  const [isOn, setIsOn] = useState(false);

  const toggle = () => {
    setIsOn(!isOn);
  };

  return (
    <div>
      <button onClick={toggle}>
        {isOn ? 'Turn Off' : 'Turn On'}
      </button>
      <p>Switch is {isOn ? 'on' : 'off'}.</p>
    </div>
  );
}

Example 2: Toggling a Boolean State

import React, { useState } from 'react';

function InputField() {
  const [inputValue, setInputValue] = useState('');

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

  return (
    <div>
      <input
        type="text"
        value={inputValue}
        onChange={handleInputChange}
        placeholder="Type something..."
      />
      <p>You typed: {inputValue}</p>
    </div>
  );
}

Example 3: Input Field with Controlled State

Exo : Dynamic progress bar

import React, { useState } from 'react';

function TemperatureConverter() {
  const [celsius, setCelsius] = useState(0);
  const [fahrenheit, setFahrenheit] = useState(32);

  const handleCelsiusChange = (event) => {
    const newCelsius = event.target.value;
    const newFahrenheit = (newCelsius * 9) / 5 + 32;
    setCelsius(newCelsius);
    setFahrenheit(newFahrenheit);
  };

  const handleFahrenheitChange = (event) => {
    const newFahrenheit = event.target.value;
    const newCelsius = ((newFahrenheit - 32) * 5) / 9;
    setFahrenheit(newFahrenheit);
    setCelsius(newCelsius);
  };
  // return part
}

Example 4: Multiple States part

return (
    <div>
      <label>
        Celsius:
        <input type="number" 
    		value={celsius} 
			onChange={handleCelsiusChange}/>
      </label>
      <br />
      <label>
        Fahrenheit:
        <input type="number" 
		value={fahrenheit} 
		onChange={handleFahrenheitChange}/>
      </label>
    </div>
  );
import React, { useState } from 'react';

function UserProfile() {
  const [user, setUser] = useState({
    firstName: '',
    lastName: '',
    email: '',
  });

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

  // return part
}

Example 5: Managing an Object State

  return (
    <div>
      <input type="text" name="firstName" value={user.firstName} 
  		onChange={handleInputChange} placeholder="First Name" />
      <input type="text" name="lastName" value={user.lastName} 
		onChange={handleInputChange} placeholder="Last Name"/>
      <input type="email" name="email" value={user.email} 
		onChange={handleInputChange} placeholder="Email" />
      <p>{`Hello, ${user.firstName} ${user.lastName}`}</p>
      <p>Email: {user.email}</p>
    </div>
  );

3. Effect Hook

The useEffect Hook in React is used to manage side effects in functional components. It allows you to perform tasks that can't or shouldn't happen within the regular rendering process. Such as :

  • Fetching data from an API.

  • Manipulating the DOM (e.g., changing the page title).
  • Subscribing to events (like clicks or scrolls).
  • Cleaning up resources (e.g., canceling subscriptions or timers).

In short

useEffect tells React: "Do something after the component renders or when certain data changes."

Basic Syntax

useEffect(() => {
  // Code to run after rendering or
  //  when dependencies change
  return () => {
    // Cleanup code (optional)
  };
}, [dependencies]); // Dependency array (optional)
  • The first argument is a function that contains the code you want to run as a side effect.
  • The second argument is an optional array of dependencies. 

Dependencies

useEffect(() => {
  // Your side effect code here
}, [dependencies]);
  • []: empty array means this effect runs only on the mount of the component.
  • [list_of_dependencies]: every time one of these dependencies changes the effect will run.
  • no array: will run on every runder.

Example 1 : On Mount

import { useEffect } from 'react';

function MyComponent() {
  useEffect(() => {
    console.log('Component is mounted.');
    
    return () => {
      console.log('Component is unmounted.');
    };
  }, []); // An empty dependency array means this effect runs only on mount
  return <div>My Component Content</div>;
}
export default MyComponent;

Example 2: Change the Page Title (DOM)

import { useState, useEffect } from 'react';

function App() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    document.title = `You clicked ${count} times`;
  }, [count]); // Dependency: `count`

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

export default App;

Example 3:

Fetch Data from

an API

import { useState, useEffect } from 'react';

function App() {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  useEffect(() => {
    fetch('https://jsonplaceholder.typicode.com/posts/1')
      .then((response) => response.json())
      .then((data) => {
        setData(data);
        setLoading(false);
      })
      .catch((error) => {
        console.error('Error:', error);
        setLoading(false);
      });
  }, []); // Empty array: runs only once
  if (loading) {
    return <p>Loading...</p>;
  }
  return (
    <div>
      <h1>{data.title}</h1>
      <p>{data.body}</p>
    </div>
  );
}
export default App;

Example 4: Clean Up an Effect

import { useState, useEffect } from 'react';

function App() {
  const [position, setPosition] = useState({ x: 0, y: 0 });
  // Add an event listener to track mouse position
  useEffect(() => {
    const handleMouseMove = (event) => {
      setPosition({ x: event.clientX, y: event.clientY });
    };
    window.addEventListener('mousemove', handleMouseMove);
    // Clean up the event listener when the component unmounts
    return () => {
      window.removeEventListener('mousemove', handleMouseMove);
    };
  }, []); // Empty array: runs only once

  return (
    <div>
      <p>Mouse position:</p>
      <p>X: {position.x}, Y: {position.y}</p>
    </div>
  );
}

export default App;

This prevents errors if the component is removed from the DOM and avoid memory leaks.

Example 5: Using Multiple useEffect Hooks

import { useState, useEffect } from 'react';

function App() {
  const [count, setCount] = useState(0);
  const [message, setMessage] = useState('');
  // Change the page title
  useEffect(() => {
    document.title = `Count: ${count}`;
  }, [count]);
  // Show a message when the counter reaches 10
  useEffect(() => {
    if (count === 10) {
      setMessage('Congratulations, you reached 10!');
    }
  }, [count]);

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

export default App;

Common Pitfalls

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

useEffect(() => {
  setCount(count + 1); // Infinite loop!
}, [count]); // `count` changes on every render
  • Forgetting Dependencies: If you forget to include a dependency in the array, useEffect won’t run when that dependency changes.
  • Infinite Loops: If you modify a dependency inside useEffect without proper handling, you can create an infinite loop.
  • Forgetting Cleanup: If you subscribe to an event or timer, don’t forget to clean it up to avoid memory leaks.

Made with Slides.com