react-notes
react-notes
Programming paradigms are fundamental to how we think about and write code.
Imperative Programming
The developer specifies every step required to achieve the desired outcome.
Declarative Programming
Developers describe the desired result without explicitly outlining the steps to achieve it.
<script>
const element = document.createElement("p");
element.textContent = "Hello, World!";
document.body.appendChild(element);
</script>
The programmer explicitly creates the element, sets its content, and appends it to the DOM.
Every change to the DOM must be coded manually, leading to verbose and error-prone scripts.
root.render(<p>Hello, World!</p>);
The developer specifies what the UI should look like in its final state.
React handles the underlying DOM manipulations, making the code simpler, cleaner, and easier to maintain.
HTML: Describes the structure of the web page (e.g., a <div> is a container).
CSS: Defines how elements should look (e.g., "Make this container blue").
React as a Single Page Application (SPA)
What is an SPA?
A Single Page Application (SPA) is a web application that loads a single HTML page and dynamically updates
the content as the user interacts with the app.
SPAs use JavaScript and frameworks like React to handle routing, state management, and dynamic content
rendering on the client side.
The server delivers one HTML file at the beginning, and further interactions are handled dynamically
via JavaScript.
2. Client-Side Routing:
SPAs use libraries like React Router to navigate between "pages" without reloading the browser.
Faster interactions because only specific components are updated, not the entire page.
SPAs leverage ReactDOM and the Virtual DOM for efficient, seamless UI updates.
Benefits of SPAs
Feature Advantages
Speed Faster page transitions without full reloads.
Smooth User Feels like a native application.
Experience
Reduced Server Load Minimizes server requests after the initial load.
Limitations of SPAs
Feature Challenges
SEO Search engines may struggle to index SPA content.
Initial Load Time Loading the entire app initially can take longer.
JavaScript Heavily reliant on JavaScript execution.
Dependency
What is SSR?
Server-Side Rendering (SSR) generates HTML content on the server for each request.
The browser receives a fully-rendered page, improving load times and SEO performance.
2. The server processes the request, runs React on the server, and generates HTML.
3. The browser receives the HTML, which is displayed immediately.
Framework Support for SSR: React frameworks like Next.js support SSR.
What is CSR?
Client-Side Rendering (CSR) is React's default behavior where JavaScript runs in the browser to dynamically
generate and render the UI.
2. The server responds with a blank HTML page and JavaScript files.
3. The browser downloads and executes the JavaScript to render the UI.
The Document Object Model (DOM) is a browser-based representation of the webpage’s structure. Direct
manipulation of the DOM with JavaScript allows developers to update elements dynamically.
Example:
<script>
const element = document.createElement("h1");
element.textContent = "Imperative Example";
document.body.appendChild(element);
</script>
React and ReactDOM: The Declarative Alternative
React introduces the Virtual DOM (VDOM), an in-memory representation of the actual DOM. ReactDOM bridges the
gap between React components and the browser’s actual DOM.
What is it? A lightweight copy of the DOM that exists in memory, allowing React to make efficient updates.
React compares the current VDOM with the previous one (a process called "diffing").
Only the elements that have changed are updated in the actual DOM (known as "reconciliation").
Direct DOM manipulations are slow because browsers re-render the entire UI for even small
changes.
React's VDOM minimizes these re-renders, making updates faster and more efficient.
ReactDOM
ReactDOM acts as a renderer that applies the Virtual DOM changes to the actual DOM.
Example:
root.render(<h1>Declarative Example</h1>);
JavaScript XML (JSX) allows you to write HTML-like syntax in JavaScript files.
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script type="text/babel">
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<h1>Carpe Diem</h1>);
</script>
Key Features
<>
</>
const box = <div style={{ color: "blue", fontSize: "20px" }}>Styled Box</div>;
React components are the building blocks of any React application. They encapsulate UI logic and presentation,
enabling developers to create reusable, modular, and maintainable interfaces. Props (short for properties) allow data
to flow from parent components to child components, making components dynamic and customizable.
Components
A React component is a JavaScript function (or class) that returns JSX. Components can be:
function Greet(props) {
return <h1>Hello, {props.name}!</h1>;
}
2. Class Components: Older, stateful components defined using ES6 classes.
Props
Props allow components to:
Example:
Key Concepts
Feature Description
Dynamic Content Props allow for rendering variable data.
Reusability Components can be reused with different props.
Unidirectional Flow Data flows from parent to child only.
Immutability Props cannot be modified by the receiving component.
Overview
React applications follow a component hierarchy, where the application is composed of multiple nested
components. This promotes:
App
├── Header
├── Product List
│ ├── Product Item
│ │ ├── Add To Cart Button
├── Footer
Component Composition
React encourages composition over inheritance, meaning components are combined to build more complex UIs.
Example:
function Navbar() {
return <div>Navbar</div>;
}
function Sidebar() {
return <div>Sidebar</div>;
}
function Content() {
return <div>Main Content</div>;
}
function App() {
return (
<>
<Navbar />
<div>
<Sidebar />
<Content />
</div>
</>
);
}
The children prop is a special prop in React that allows developers to pass any JSX or components between the
opening and closing tags of a parent component.
Example:
Use Cases
Conditional Rendering
if-else Statements:
function Message({ isLoggedIn }) {
if (isLoggedIn) {
return <p>Welcome back!</p>;
} else {
return <p>Please log in.</p>;
}
}
Ternary Operator:
Conditional Styling
Code Implementation:
function Header() {
return <header>Blog Header</header>;
}
function Footer() {
return <footer>Blog Footer</footer>;
}
function BlogCard({ title, content, isFeatured }) {
const cardStyle = {
border: "1px solid gray",
padding: "10px",
backgroundColor: isFeatured ? "lightyellow" : "white",
};
return (
<div style={cardStyle}>
<h2>{title}</h2>
<p>{content}</p>
</div>
);
}
function App() {
const blogs = [
{ title: "React Basics", content: "Learn the basics of React.", isFeatured: true },
{ title: "Advanced React", content: "Delve deeper into React.", isFeatured: false },
];
return (
<>
<Header />
<main>
{blogs.map((blog, index) => (
<BlogCard
key={index}
title={blog.title}
content={blog.content}
isFeatured={blog.isFeatured}
/>
))}
</main>
<Footer />
</> );
}ReactDOM.createRoot(document.getElementById("root")).render(<App />);
Introduction
In React, form elements like inputs, textareas, and select elements can be managed in two ways:
1. Controlled Components: React fully manages the state of the form element.
2. Uncontrolled Components: The DOM itself manages the state of the form element.
Understanding these two approaches is crucial for building forms in React effectively.
Controlled Components
Definition:
In controlled components, the value of a form element is controlled by React state. The component's state acts as the
"single source of truth."
Key Features:
Example:
function ControlledForm() {
const [inputValue, setInputValue] = useState('');
const handleChange = (e) => {
setInputValue(e.target.value);
};
const handleSubmit = (e) => {
e.preventDefault();
console.log(`Submitted Value: ${inputValue}`);
};
return (
<form onSubmit={handleSubmit}>
<label>
Name:
<input type="text" value={inputValue} onChange={handleChange} />
</label>
<button type="submit">Submit</button>
</form>
);
}
export default ControlledForm;
How It Works:
1. The value attribute of the <input> is tied to the React state (inputValue).
2. When the user types, the onChange handler updates the state.
3. React re-renders the component with the updated state, ensuring the input reflects the current state.
Advantages:
Single Source of Truth: React state controls the form, making data flow predictable.
Disadvantages:
Verbose Code: Requires additional state and handlers for every input.
Uncontrolled Components
Definition:
In uncontrolled components, the form element's state is managed by the DOM itself. React accesses the value
through a ref.
Key Features:
Example:
How It Works:
2. The ref (inputRef) provides access to the input value when needed.
Advantages:
Use Cases: Ideal for simple forms or when integrating with non-React libraries.
Disadvantages:
Limited React Control: React has less control over the form element's behavior.
4. Key Differences
Dynamic forms where input values affect other parts of the UI.
When integrating with non-React libraries that rely on direct DOM manipulation.
6. Mixing Controlled and Uncontrolled Components
In some cases, you might combine both approaches to balance simplicity and control. For example, a form might
have some inputs managed by React state and others accessed via refs.
Example:
7. Summary Table
Definition: State represents dynamic data or "the memory" of a React component. It determines how a
component behaves and renders based on changes.
Example: A button's label toggling between "Start" and "Stop" is determined by state.
1. Dynamic UIs: State enables components to react to user interactions, such as clicks or form inputs.
2. Component Isolation: State allows components to encapsulate and manage their own data independently.
3. Reactivity: React automatically re-renders components when state changes, ensuring the UI stays up-to-date.
function Counter() {
let count = 0;
function increment() {
count++;
console.log(count); // No UI update
}
return <button onClick={increment}>Count: {count}</button>;
}
With State:
function Counter() {
const [count, setCount] = React.useState(0);
function increment() {
setCount(count + 1); // Triggers UI re-render
}
return <button onClick={increment}>Count: {count}</button>;
}
Hooks are special functions introduced in React 16.8 to enable state and side effects in functional components.
What is useState?
Syntax:
1. Initial State: Can be any data type (string, number, object, array, etc.).
2. State Setter Function: Replaces the current state with a new value.
Example:
function Example() {
const [count, setCount] = React.useState(0);
function increment() {
setCount(count + 1);
}
return <button onClick={increment}>Count: {count}</button>;
}
3. Examples of State Management
String State:
function Greeting() {
const [name, setName] = React.useState("Guest");
return (
<div>
<p>Hello, {name}!</p>
<button onClick={() => setName("Alice")}>Set Name</button>
</div>
);
}
Boolean State:
function Toggle() {
const [isOn, setIsOn] = React.useState(false);
return (
<button onClick={() => setIsOn(!isOn)}>
{isOn ? "Switch Off" : "Switch On"}
</button>
);
}
Working with Arrays
function UserProfile() {
const [user, setUser] = React.useState({ name: "Alice", age: 25 });
function updateAge() {
setUser({ ...user, age: user.age + 1 });
}
return (
<div>
<p>Name: {user.name}</p>
<p>Age: {user.age}</p>
<button onClick={updateAge}>Increase Age</button>
</div>
);
}
function TodoList() {
const [todos, setTodos] = React.useState([]);
function addTodo() {
const newTodo = { id: todos.length + 1, task: `Task ${todos.length + 1}` };
setTodos([...todos, newTodo]);
}
return (
<div>
<button onClick={addTodo}>Add Todo</button>
<ul>
{todos.map((todo) => (
<li key={todo.id}>
{todo.task}
</li>
))}
</ul>
</div>
);
}
Updating an Item in an Array of Objects:
function UpdateTodo() {
const [todos, setTodos] = React.useState([
{ id: 1, task: "Learn React", completed: false },
]);
function toggleComplete(id) {
setTodos(
todos.map((todo) =>
todo.id === id ? { ...todo, completed: !todo.completed } : todo
)
);
}
return (
<ul>
{todos.map((todo) => (
<li key={todo.id}>
<span style={{ textDecoration: todo.completed ? "line-through" : "none" }}>
{todo.task}
</span>
<button onClick={() => toggleComplete(todo.id)}>
{todo.completed ? "Undo" : "Complete"}
</button>
</li>
))}
</ul>
);
Manage state within the component that needs it. Lift it up only if necessary.
2. Avoid Overuse:
Not every piece of data needs to be in state (e.g., constants, derived data).
Use simpler states or multiple smaller states instead of deeply nested ones when possible.
Summary
The useState hook allows functional components to manage and update state.
React supports state management for various data types, from strings to complex arrays of objects.
This application combines everything discussed above: useState, state management for arrays of objects, and
dynamic UI updates with React. It serves as a practical implementation of state management concepts.
Application Features
Code Implementation
function App() {
const [tasks, setTasks] = useState([]);
const [taskInput, setTaskInput] = useState("");
return (
<div className="app">
<h1>To-Do List</h1>
useRef
Introduction
useRef is a React Hook designed to manage references to DOM elements or store values across component renders
without triggering re-renders. It serves as a container for mutable data that remains consistent across re-renders,
akin to a "box" that safely holds a value. This hook is particularly useful for accessing DOM elements directly,
managing focus, or storing values like timers or animation frames that do not directly influence the component's
output.
Detailed Explanation
What is useRef?
useRef is part of React's Hooks API, allowing developers to maintain a consistent reference to a value or a DOM
element throughout the component's lifecycle. It returns a mutable object with a .current property, which can be
initialized with a value of any type. Unlike state updates with useState, updates to a useRef value do not cause the
component to re-render, making it ideal for keeping track of values or DOM elements that do not directly impact the
visual output of the component.
Basic Syntax
Why is it useful?
useRef provides a way to persist values across renders without triggering re-renders, offering a performance benefit
for certain operations like accessing DOM elements, storing previous state for comparison, or keeping track of values
that don't need to trigger visual updates. It's a critical tool for handling imperatives, such as focus management or
integrating with third-party DOM libraries.
1. Form Input Focus: Automatically focus a text input when a component loads.
3. Comparing Props: Compare current props with previous ones to decide on rendering logic.
4. Building Custom Element say a custom video player and managing it.
Consider useRef as a personal notebook that you carry throughout the day. You can jot down notes (values) in it,
refer back to them whenever needed, or even replace them with new notes. The notebook remains the same (the
reference doesn't change), and your actions of writing or reading from it don't announce themselves to the world (do
not cause re-renders).
Great question! The main difference between useState and useRef is that useState will cause your component to re-
render when the state changes. useRef doesn't do that. It's like a silent ninja, keeping your value safe without making
a fuss.
Let’s understand with simpler example the working of useRef along with useState
useState useRef
Value persists through re-renders Value persists through re-renders
Changing the value triggers a re-render Changing the value does not trigger a re-render
Perfect for storing information that is required for UI Perfect for storing information that is not required directly
Example : Say you want to display count or some for UI Example : Maybe some intervalId you have to store .
data. Storing that data in useState makes more sense. or some subscriptionId or some other id you want to
Reason being when this value changes, the store. This value persists through re-renders and you
component re-renders and in browser you’ll the might be needing to cleanup stuff during
latest value being updated unmount/updates.
Syntax : Initial Declaration :let someRef = Syntax : Initial Declaration :let someState =
useRef( initialValue ) Return value someRef : useState( initialValue ) Return value someState : [ state,
{ current: initialValue }. It returns an object with key setState ] It returns an array with two values. state whose
“current” and value will be the initialValue that you value will be the initalValue and setState which is a
passed inside ref function which updates state value
Immutable - one must use the state setting function Mutable : you can modify the current property manually
to modify state variable
Accessing DOM Elements
useRef can be used to focus an input element on the initial render of a component. For instance:
import { useRef, useEffect } from "react";
function TextInputWithFocus() {
const inputEl = useRef(null);
useEffect(() => {
// Automatically focus the input using the useRef hook
inputEl.current.focus();
}, []);
useRef is also handy for keeping any mutable value around for the lifetime of the component. For example, tracking
the number of times a component has rendered:
function RenderCounter() {
const renderCount = useRef(0);
useEffect(() => {
// Increment the render count on each render
renderCount.current++;
});
return <h5>Render Count: {renderCount.current}</h5>;
Example 1 It can be super helpful if we need to store id of Timer ( Something which we have built previously ). It can
be done this way ( Since the value of ref persists across re-renders )
function startTimer() {
ref.current = setInterval(() => {
// do something
});
}
function stopTimer() {
clearInterval(ref.current);
ref.current = null;
}
Example 2
import { useEffect, useState, useRef } from "react";
function Timer() {
const [count, setCount] = useState(10);
const intervalRef = useRef(null);
useEffect(() => {
const cleanup = () => {
stopTimer();
};
return cleanup;
}, []);
Example 1 :
1. useRef hook allows you to keep a mutable value in it’s .current property
2. Create an application wherein you add video element. You do know that can access DOM nodes
with useRef hook. So here in the application as well, please access video DOM notes using this
hook useReflike this
3. Now you’ll create two buttons PLAY and PAUSE . clicking on PLAY button will call onPlay event handler.
Similarly clicking on PAUSE button will call onPause event handler. This event
handler onPlay and onPause will play and pause the video ( This you will do by accessing the video node and
then HTMLMediaElement: play() method and HTMLMediaElement: pause() method method )
const handlePlay=()=>{
inputEle.current.play();
}
const handlePause=()=>{
inputEle.current.pause()
}
const handleReset=()=>{
inputEle.current.currentTime = 0;
inputEle.current.play();
return (
<div>
<video
ref={inputEle}
content='false'
style={{width: "600px" , border: "1px solid #ccc" }} >
<source
src="https://www.w3schools.com/html/mov_bbb.mp4"
type='video/mp4'/>
</video>
<div>
<button onClick={handlePlay} > Play </button>
<button onClick={handlePause} > Pause </button>
<button onClick={handleReset} > Reset </button>
</div>
</div>
)
}
React provides a structured way of building UIs compared to vanilla JavaScript, which often involves direct
manipulation of the DOM. React uses a Virtual DOM to efficiently update only parts of the UI that have changed,
while JavaScript directly interacts with the actual DOM, which can be slower and more error-prone. React also
emphasizes declarative code, making it easier to reason about the state of the application.
- Javascript -
// Directly manipulates the DOM element and updates its text content
function MyComponent() {
return <div>Updated Text</div>;
}
2. Handling Side Effects
- Javascript -
// Manages side effects like fetching data directly inside the function
function fetchData() {
// Directly call API and handle response
}
- React -
useEffect(() => {
fetchData(); // Fetches data after the component renders
}, []); // Runs once on component mount
Side effects are managed in React using the useEffect hook, which allows you to perform actions after the component
renders, ensuring side effects are kept separate from rendering logic.
useEffect is a React hook that lets you perform side effects in function components. It runs after the component
renders and can handle operations like fetching data, setting up subscriptions, and cleaning up resources. By
providing a dependencies array, you can control when the effect runs, ensuring that side effects are executed at the
appropriate times.
Ex
useEffect(() => {
// Side effect code here, e.g., fetching data or updating the DOM
return () => {
// Cleanup code here (optional), runs when the component unmounts or dependencies change
};
}, [dependencies]); // Dependencies array specifies when to re-run the effect
Lifecycle Phases:
React components go through various lifecycle phases, including mounting, updating, and unmounting.
Understanding these phases is crucial for managing component behavior, especially when dealing with side effects,
state changes, and cleanup operations. The useEffect hook allows functional components to mimic these lifecycle
methods, enabling efficient and predictable component management.
Mounting: When a component is being inserted into the DOM (e.g., componentDidMount in class components).
Unmounting: When a component is being removed from the DOM (e.g., componentWillUnmount).
Ex -
import React, { useEffect } from 'react';
function MyComponent() {
useEffect(() => {
console.log('Component did mount'); // Runs once when the component mounts
return () => {
console.log('Component will unmount'); // Runs when the component is about to unmount
};
}, []); // Empty dependencies array ensures it runs only once on mount
return <div>Hello</div>;
}
In React development, effectively managing the lifecycle of components is crucial for optimizing application
performance and preventing memory leaks. This lesson focuses on the unmount phase of component lifecycle and
demonstrates how to use the useEffect hook for cleanup, particularly important for releasing resources and stopping
background activities when components are removed from the UI.
Detailed Explanation
The unmount phase occurs when a component is removed from the DOM. Similar to turning off unnecessary
appliances when leaving a room, this phase is critical for cleaning up resources allocated by the component, such as
timers, event listeners, or subscriptions.
React's useEffect hook not only allows us to perform side effects after rendering but also provides a mechanism for
cleanup via a return function. This cleanup function is executed when the component is unmounted, making it an
ideal place to release resources and prevent memory leaks.
Consider a countdown timer component that starts counting down from 10 to 0 upon mounting. Without proper
cleanup, the interval set to update the countdown can continue running even after the component is unmounted,
leading to a memory leak.
Without cleanup, the interval continues to run in the background even after the Timer component is unmounted,
consuming resources unnecessarily and potentially leading to application performance issues.
Implementing Cleanup
To prevent this, we can use a cleanup function in useEffect to clear the interval when the component unmounts:
function Timer() {
useEffect(() => {
const intervalId = setInterval(() => {
console.log(`This code runs every 1 second`, Date.now());
}, 1000);
// Cleanup function
return () => {
clearInterval(intervalId);
};
}, []);
return <h1>Timer</h1>;
}
Why Use Callback Function with setState
Using a callback function with setState (setCount(prevCount => prevCount - 1)) ensures that we always have the
most current state value. This approach helps avoid issues related to stale state, especially in asynchronous
operations like intervals or fetch requests.
In the improved Timer component example, the countdown stops when it reaches 0, and the interval is cleared:
function Timer() {
const [count, setCount] = useState(10);
useEffect(() => {
const intervalId = setInterval(() => {
setCount((prevCount) => {
if (prevCount === 1) {
clearInterval(intervalId);
return prevCount - 1;
}
return prevCount - 1;
});
}, 1000);
return (
<div>
<h3>Count: {count}</h3>
</div>
);
Using React and the useEffect hook, create a functional component that fetches and displays a random
joke from an external API (e.g., https://official-joke-api.appspot.com/random_joke).
1. Display the joke in a card format.
2. Add a button labeled "Get Another Joke" that, when clicked, fetches a new joke.
3. Ensure the API call is handled inside useEffect.
useEffect(()=>{
fetchJoke();
},[FetchJoke])
return (
<div className='Container'>
<div className='Container-card'>
{ joke ? (
<>
<h1 className='title'> Random Joke</h1>
<p className='text'><strong>Setup: </strong>{joke.setup}</p>
<p className='text'> <strong> Punchline: </strong> {joke.punchline}</p>
</>
):(
<p> ... Loading</p>
)
}
</div>
<button onClick={()=> setFetchJoke(!FetchJoke)}>Get Another Joke</button>
</div>
)
}
In React development, managing state across multiple components is a common challenge. Props drilling and Context
API are two approaches to tackle this issue. This lesson explores these concepts, their relevance, and importance in
efficient React app development.
Detailed Explanation
Props drilling occurs when you need to pass data from a parent component down to deeply nested child
components, potentially through multiple levels of components that do not need the data themselves. It's like
passing a message down a line of people where only the last person needs to hear it. This approach can quickly
become cumbersome and lead to tightly coupled code that is difficult to maintain.
Why is it a problem?
Reduces Component Reusability: Components become less generic and harder to reuse in other contexts
because they rely on props passed down from their parents.
Risk of Missing Props: It's easy to forget to pass props through every level of the component tree, leading to
runtime errors and bugs.
The Context API provides a way to share values like these between components without having to explicitly pass a
prop through every level of the tree. With Context, you can store "global" data that can be accessed by any
component in the component tree, regardless of how deeply nested it is.
Why is it useful?
Improves Code Maintainability: By avoiding props drilling, Context API makes your code more maintainable
and the component tree cleaner.
Enhances Component Reusability: Components can consume context data directly without relying on props
passed from parent components, making them more reusable across different parts of your application.
Imagine a simple component hierarchy where App passes its state down to a BottomMainRight component.
Project Structure :
└── 📁src
└── App.css
└── App.jsx
└── 📁components
└── BottomMain.jsx
└── BottomMainLeft.jsx
└── BottomMainRight.jsx
└── Footer.jsx
└── Main.jsx
└── Navbar.jsx
└── TopMain.jsx
└── index.css
└── main.jsx
Code Implementation :
// App.jsx
import { useState } from "react";
import Navbar from "./components/Navbar";
import Main from "./components/Main";
import Footer from "./components/Footer";
import "./App.css";
function App() {
const isLoggedIn = useState(true);
return (
<>
<Navbar />
<Main isLoggedIn={isLoggedIn} />
<Footer />
</>
);
}
function BottomMain() {
return (
<div>
BottomMain
<BottomMainLeft />
<BottomMainRight />
</div>
);
}
Props Drilling
Exploring these resources will deepen your understanding of props, context, and their roles in React development.
Context API
Introduction
In modern web development, especially with React, managing state and data flow across components can become
complex as applications scale. The Context API in React offers a powerful solution to share data efficiently throughout
the component tree, without resorting to props drilling. This lesson will guide you through setting up and using the
Context API with a focus on managing login states across components.
Detailed Explanation
The Context API is a React feature that enables components to share some global data without having to pass props
down manually through every level of the component tree. This approach significantly simplifies data flow and
component structure, especially in large applications.
Why is it useful?
Simplified Data Flow: By avoiding props drilling, the Context API makes data sharing across components
easier and more direct.
Enhanced Component Reusability: It decouples components from their parents, making them more modular
and reusable.
Better Code Maintenance: It makes the codebase cleaner and the data flow within the app more
understandable and easier to debug.
Real-world Examples
User Authentication State: Managing whether a user is logged in and sharing this state across components
that need to know the user's authentication status.
Theme Management: Storing the current UI theme settings (e.g., light or dark mode) and applying it across
the entire application.
Library Integration: Tools like react-router-dom use Context API under the hood to manage routing
information across components.
Benefits
1. Simplified Data Flow: The need for passing props through every level is eliminated, streamlining the process
of data sharing.
3. Improved Code Maintenance: The straightforward data flow enhances code readability and ease of
maintenance.
Purpose: To initialize a React Context that will store the global data you want to share.
Purpose: To make the created context available throughout the component tree.
ReactDOM.createRoot(document.getElementById("root")).render(
<AuthContextProvider>
<App />
</AuthContextProvider>
);
Step 3: Consume
Purpose: To access and utilize the context data in any component within the provided tree.
function BottomMainLeft() {
const { isLoggedIn } = React.useContext(AuthContext);
// Additional component code
}
Visualizing Data Flow with Context API
The included diagram illustrates how data is seamlessly shared across components using the Context API, bypassing
the constraints of props drilling.
Student Activities
Implement Theme Context: Create a simple application with the Context API to toggle between light and
dark themes across all components.
User Authentication Practice: Build a small app that uses the Context API to manage user authentication
state, displaying different UI elements based on the user's login status.
Conclusion
The Context API represents a significant leap forward in React development, offering a streamlined approach to state
management and data sharing. By following the CPC methodology, developers can enhance their applications'
scalability, maintainability, and overall architecture. Engaging with real-world examples and hands-on activities
further solidifies the understanding and application of this powerful API.
Resources
useContext
Create Context
These resources offer in-depth knowledge and additional patterns for effectively utilizing the Context API in your
React projects.
Introduction
When building complex applications, you might find yourself needing to manage different types of global states, such
as authentication status and UI themes. This lesson covers how to effectively use multiple contexts within a single
React application, using AuthContext for authentication and ThemeContext for theme management as examples.
Detailed Explanation
In App.jsx, wrap your component tree with both AuthContextProvider and ThemeContextProvider.
<AuthContextProvider>
<ThemeContextProvider>
{/* Rest of your app components */}
</ThemeContextProvider>
</AuthContextProvider>
Step 3: Consuming Contexts in Components
Context values can be updated using setters provided in the respective context providers.
Student Activities
Implement a Language Context: Add a third context to manage the language settings of your application.
Allow components to switch between languages, demonstrating the application's internationalization
capability.
Theme Customization Feature: Extend the ThemeContext to allow users to customize and save their theme
preferences, such as primary colors and font sizes.
Conclusion
Using multiple contexts in a React application enables the efficient management of different global states, such as
user authentication and theme settings. This structured approach not only enhances the application's scalability and
maintainability but also improves overall code readability and component reusability. Following best practices such
as minimizing context values and optimizing through useMemo or useCallback ensures that your application remains
performant.
Resources
These resources provide deeper insights into React's Context API and offer practical examples and patterns for
effectively managing global state in large applications.
Chakra UI is a popular, modular, and accessible component library for React applications that simplifies the process of
building beautiful and responsive UIs. It provides a set of out-of-the-box components that are both easy to use and
customize, enabling developers to build their applications faster and more efficiently. In this lesson, we'll explore how
to install Chakra UI, utilize its style props for styling components directly, and delve into some of its fundamental
layout components.
Detailed Explanation
Chakra UI is a front-end framework that offers a collection of simple, modular, and accessible React components.
Designed with ease of use and flexibility in mind, it allows developers to create engaging user interfaces with minimal
effort.
Why is it useful?
Chakra UI is built with accessibility in mind, ensuring that applications are accessible to as many people as possible.
Its style props system enables developers to style components directly with props, streamlining the development
process. Furthermore, its component library covers a wide range of UI needs, from simple layout components to
complex interactive elements, making it a versatile tool for developers.
Think of Chakra UI as the Lego set of the React world. Just as Legos allow you to build complex structures with
simple, interlocking pieces, Chakra UI provides the building blocks for creating complex UIs with simple, composable
components.
1. Installation: Start by adding Chakra UI to your React project with npm or yarn:
# or
2. Setup: Wrap your application with the ChakraProvider at the root level to enable Chakra UI throughout your
app.
Layout Components :
These components simplify the process of building responsive layouts in React applications. They leverage the power
of Flexbox and CSS Grid with an easy-to-use API, enabling developers to quickly create complex layouts that are both
responsive and accessible. By abstracting away the traditional complexities of CSS, Chakra UI's layout components
allow developers to focus more on functionality rather than styling.
Box
Box: The foundation of all Chakra UI layout components, acting as a div with access to style props. It's used for
wrapping elements and applying basic styles like padding, margin, colors, and more.
A simple Box to create a container with padding, background color, and text color:
Flex
Flex: A Box component with display: flex style applied. It's used for creating flexible layouts and aligning items both
horizontally and vertically, offering control over spacing, alignment, and distribution of child elements.
Flex Component Example
Creating a navbar layout using Flex to align items center and space them evenly:
Grid
Grid: An extension of the Box component with display: grid. It allows for more complex layouts compared to Flex,
providing capabilities for defining grid columns, rows, gaps, and areas.
</Grid>
https://chakra-ui.com/docs/components/grid/usage
Stack
Stack: A higher-level component built on top of the Flex component. It's designed to make it easier to stack elements
vertically or horizontally with consistent spacing, without needing to manually manage margins or paddings.
<Stack spacing={4}>
<Input placeholder="Your Name" />
<Input placeholder="Your Email" />
<Button colorScheme="blue">Submit</Button>
</Stack>
https://chakra-ui.com/docs/components/stack/usage
Form Components
These form components are designed with usability and accessibility in mind, ensuring that form elements are easy
for users to interact with, regardless of their device or assistive technologies they may use. By utilizing Chakra UI's
form components, developers can quickly implement forms that are both functional and aesthetically pleasing, with
minimal effort required for customization and styling.
These form components are designed with usability and accessibility in mind, ensuring that form elements are easy
for users to interact with, regardless of their device or assistive technologies they may use. By utilizing Chakra UI's
form components, developers can quickly implement forms that are both functional and aesthetically pleasing, with
minimal effort required for customization and styling.
https://chakra-ui.com/docs/components/input/usage
Button: A crucial component for submitting forms or triggering actions. Chakra UI buttons can be customized
in terms of size, color, and functionality.
Select: Allows users to choose from a dropdown list of options. This component is essential for forms where
users must select from predefined options.
Radio: Enables selection among a group of options. Only one option can be selected at a time, making it ideal
for mutually exclusive choices.
function RadioExample() {
const [value, setValue] = React.useState("1");
return (
<RadioGroup onChange={setValue} value={value}>
<Stack direction="row">
<Radio value="1">First</Radio>
<Radio value="2">Second</Radio>
<Radio value="3">Third</Radio>
</Stack>
</RadioGroup>
);
}
https://chakra-ui.com/docs/components/radio/usage
Checkbox: Used for selections where multiple choices are allowed. Checkboxes are perfect for options that
can be combined or applied independently.
<Checkbox defaultChecked>Checkbox</Checkbox>
https://chakra-ui.com/docs/components/checkbox/usage
Overlay Components
Modal
A modal is a dialog that focuses the user's attention exclusively on an information via a window that is overlaid on
primary content.
function BasicUsage() {
const { isOpen, onOpen, onClose } = useDisclosure();
return (
<>
<Button onClick={onOpen}>Open Modal</Button>
<ModalFooter>
<Button colorScheme="blue" mr={3} onClick={onClose}>
Close
</Button>
<Button variant="ghost">Secondary Action</Button>
</ModalFooter>
</ModalContent>
</Modal>
</>
);
}
Reference : https://chakra-ui.com/docs/components/modal/usage
useReducer
What is useReducer?
useReducer is a React Hook used to manage complex state logic by reducing state updates to a predictable flow using
a reducer function.
Key Components
2. Reducer Function: A function that takes the current state and an action, and returns the new state.
Syntax
function Counter() {
const [state, dispatch] = useReducer(reducer, { count: 0 });
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: 'increment' })}>Increment</button>
<button onClick={() => dispatch({ type: 'decrement' })}>Decrement</button>
</div>
);
}
What is an Action?
An action is a plain JavaScript object that describes what should be done to update the state.
Structure of an Action
const action = {
type: 'ACTION_TYPE',
payload: { /* additional data */ }
};
type (required): A string describing the action.
const action = {
type: 'add_todo',
payload: { id: 1, text: 'Learn React' },
};
What is dispatch?
The dispatch function is used to send an action to the reducer function. It triggers a state update by invoking the
reducer.
2. The reducer processes the action and returns the updated state.
Syntax
dispatch(action);
Example: Counter
What is a Reducer?
A reducer is a pure function that determines the next state based on the current state and an action.
Key Characteristics
It must not mutate the state.
Structure
Purpose of payload
To-Do Example
useState vs useReducer
Complex State Logic: Optimal for situations demanding intricate state logic or multiple state dependencies.
Predictable State Transitions: The dispatch-action framework ensures clear, predictable state updates.
Scalable State Management: As application complexity increases, useReducer maintains orderly and
manageable state architecture.
The transition from using useState to useReducer in a Counter application serves as a prime example
of useReducer's structured state management capabilities.
function Counter2() {
const [state, dispatch] = useReducer(reducer, 0);
return (
<>
<h1>Counter: {state}</h1>
<button onClick={handleIncrement}>INCREMENT</button>
<button onClick={handleDecrement}>DECREMENT</button>
</>
);
}
export { Counter2 };
Transforming a data-fetching operation from useState to useReducer exemplifies managing related state variables
(loading, data, err) more cohesively:
const initState = {
loading: false,
data: [],
err: false,
};
useEffect(() => {
fetchAndUpdateData(`https://jsonplaceholder.typicode.com/posts?_limit=10`);
}, []);
return loading ? (
<h1>Loading..</h1> ) : err ? (
<h1>Something went wrong</h1> ) : (
<div className="App">
{data.map((post) => (
<p key={post.id}>
{post.id} - {post.title}
</p> ))}
</div> );
}