React Fundamentals: A Crash Course for Beginners
Introduction to React
Welcome to the React Fundamentals Crash Course, designed for individuals with no prior experience in React. This course aims to equip complete beginners with a solid understanding of React’s core concepts, enabling you to embark on your journey as a front-end web developer. React is a highly sought-after JavaScript library in the web development industry, making this a valuable skill to acquire.
This course is a continuation of HTML, CSS, and JavaScript crash courses. Therefore, familiarity with these foundational web technologies is essential before proceeding. A basic understanding of modern JavaScript (ES2015+) features will also be beneficial but not strictly required.
This crash course will focus on fundamental concepts relevant to beginners. React is a vast library with advanced topics that can be overwhelming initially. We will concentrate on the essential knowledge needed to get started and build a foundation for further exploration.
We will be using React version 18, the latest stable release as of March 29th, 2022. While version 18 introduces new features, we will only cover those pertinent to beginners, ensuring the focus remains on core fundamentals without unnecessary complexity.
This is a comprehensive crash course, and its length reflects the depth of content covered. It is recommended to learn at your own pace, pausing and practicing as needed. Coding along with the examples is strongly encouraged as it is the most effective way to learn and solidify your understanding.
By the end of this course, you will have a robust grasp of React fundamentals, setting you up for further learning and practical application.
What is React?
React is defined as:
React is an open-source JavaScript library for building user interfaces. It is specifically designed for creating interactive and dynamic web UIs.
Let’s break down this definition into key components:
-
JavaScript Library, Not a Framework: React is specifically a library, focusing on a singular purpose: building user interfaces (UIs). It excels at this task, offering tools and patterns for efficient UI development. Unlike frameworks, which provide a more comprehensive structure for entire applications, React concentrates on the view layer.
Library vs. Framework: A library is a collection of pre-written code that provides specific functionalities, allowing developers to pick and choose what they need. A framework is a more comprehensive structure that dictates the architecture of an application and provides a complete set of tools and guidelines.
-
Building User Interfaces: React’s primary focus is on creating rich and interactive user interfaces for web applications. It manages the view layer of your application, handling how users interact with and perceive your web application.
While React excels at UI development, it does not inherently handle other aspects of web application development such as routing or HTTP requests. However, React boasts a vibrant ecosystem:
Ecosystem: In the context of software, an ecosystem refers to a collection of related tools, libraries, frameworks, and community resources that work together harmoniously and extend the functionality of a core technology.
This ecosystem ensures React integrates seamlessly with other libraries to build comprehensive, enterprise-scale web applications.
Why Learn React?
There are compelling reasons to learn React, both practical and technical:
-
Job Market Demand: React is one of the most popular UI libraries in the web development industry. Proficiency in React significantly enhances your employability and opens doors to numerous front-end developer roles.
-
Strong Community Support: React benefits from a large and active community. This vast community provides abundant resources, including articles, tutorials, and solutions on platforms like Stack Overflow, ensuring you can find help and guidance when facing challenges.
-
Component-Based Architecture: React employs a component-based architecture:
Component-Based Architecture: A software design approach that structures an application as a collection of independent, reusable, and encapsulated modules called components. Each component is responsible for a specific part of the UI and functionality.
This architecture offers several advantages:
- Modularity: Applications are broken down into smaller, manageable, and encapsulated parts (components), simplifying development and maintenance.
- Composability: Components can be combined and nested to create complex user interfaces from simpler building blocks.
- Reusability: Components are designed to be reusable across different parts of an application or even in different projects, promoting code efficiency and consistency.
-
Declarative Nature: React is declarative:
Declarative Programming: A programming paradigm where you express what you want to achieve without explicitly describing how to achieve it. You describe the desired outcome, and the system figures out the steps to get there.
In React, you describe the desired UI state in your code, and React, along with React DOM:
React DOM: A package that serves as the entry point to the DOM and server renderers for React. It is responsible for rendering React components in the web browser’s Document Object Model (DOM).
abstracts away the complexities of directly manipulating the browser’s Document Object Model (DOM). React handles the intricate updates and rendering processes, making UI creation more intuitive and less error-prone.
In essence, learning React is a valuable investment, enhancing your skillset and opening opportunities in the dynamic field of web development.
Setting Up Your Development Environment
To begin developing React applications, you need to set up your development environment. This involves installing three essential tools:
-
Web Browser: A modern web browser is necessary to view and interact with your React applications. Google Chrome is recommended, but any modern browser such as Firefox, Safari, or Edge will suffice.
-
Node.js: Node.js is a JavaScript runtime environment that is crucial for React development.
- Installation:
- Navigate to nodejs.org.
- Download and install the LTS (Long-Term Support) version, which is the recommended stable release.
- Follow the installation prompts, typically accepting the default settings.
- Installation:
-
Code Editor: A code editor provides a user-friendly environment for writing and managing code. Visual Studio Code (VS Code) is a highly recommended and popular choice for React development.
- Installation:
- Navigate to code.visualstudio.com.
- Download and install VS Code for your operating system.
- After installation, open VS Code and install the Prettier extension from the Extensions panel. Prettier automatically formats your code, improving readability and consistency.
- Installation:
Once these tools are installed, create a new folder on your computer to house your React projects (e.g., “react-crash-course”). Open this folder in VS Code.
Creating Your First React Application
React applications are often created using Create React App:
Create React App (CRA): A command-line interface tool provided by Facebook (now Meta) that simplifies the process of setting up a new React project. It automatically configures the build process, development server, and other essential tools, allowing developers to start building React applications quickly without complex configurations.
Create React App streamlines the setup process, allowing you to focus on writing React code rather than configuration.
Follow these steps to create your first React application:
-
Open Integrated Terminal: In VS Code, open the integrated terminal by selecting View > Terminal.
-
Run Create React App Command: In the terminal, execute the following command:
npx create-react-app react-demo
npx: npx is a package runner tool that comes with npm (Node Package Manager). It allows you to execute Node.js packages without installing them globally. In this case, it runs
create-react-app
directly from the npm registry.This command will create a new folder named “react-demo” containing a pre-configured React application. This process may take a few moments as it sets up the project structure and installs necessary dependencies.
-
Navigate to Project Folder: Once the command completes, navigate into the newly created project folder:
cd react-demo
-
Start the Development Server: Start the React development server with the command:
npm start
npm (Node Package Manager): npm is the default package manager for Node.js. It is used to install, manage, and share JavaScript packages. The
npm start
command typically runs a script defined in thepackage.json
file to start the development server for a React application.This command will compile your React application and automatically open it in your default web browser, usually at
localhost:3000
:localhost: localhost is a hostname that refers to the computer you are currently using. In web development, localhost:3000 typically indicates that a web server is running on your local machine, and port 3000 is the specific port number being used to access the application.
You should see the default React application running, displaying the message “Edit
src/App.js
and save to reload.” -
Modify
App.js
: In VS Code, expand the “src” folder in your project and open theApp.js
file. Locate the text within thereturn
statement and change it to “Hello World”. Save the file (Ctrl+S or Cmd+S). -
Observe Changes in Browser: As soon as you save
App.js
, the browser will automatically refresh, and you should now see “Hello World” displayed in the browser window.
Congratulations! You have successfully created and run your first React application.
Understanding the Application Folder Structure
Let’s explore the structure of a React application created with Create React App. At the root level, you’ll find several folders and files:
Key Files
-
package.json
: This file is the heart of your Node.js project and, therefore, your React application. It contains:-
Dependencies: Lists the libraries your project relies on, including
react
andreact-dom
(version 18 in this case). These are essential for building React applications. -
Scripts: Defines commands you can run using
npm
, such asstart
(to run the development server),build
(to create a production build), andtest
(to run tests). -
eslintConfig
: Configuration for ESLint:ESLint: A popular linting tool for JavaScript and JSX. Linting is the process of statically analyzing code to identify potential errors, stylistic inconsistencies, and code quality issues. ESLint helps maintain code consistency and catch potential bugs early in development.
-
browserslist
: Specifies the browsers your application should support, ensuring compatibility across different browser environments.
-
-
package-lock.json
oryarn.lock
: These files (one will be present depending on whether you use npm or Yarn package manager) ensure consistent dependency installation across different environments. They lock down the specific versions of dependencies used, preventing unexpected issues due to dependency updates. You generally don’t need to directly interact with these files. -
.gitignore
: This file specifies intentionally untracked files that Git should ignore. This commonly includes dependency folders (node_modules
), build output, and other non-essential files. -
README.md
: A standard readme file:Readme File: A text file, typically named
README.md
(using Markdown formatting), that provides essential information about a project. It usually includes a project description, instructions for setup and usage, and other relevant details for users and developers.It usually contains basic information about your React application.
Key Folders
-
node_modules
: This folder houses all the dependencies:Dependencies: In software development, dependencies are external libraries, packages, or modules that a project relies on to function correctly. These are typically installed and managed using package managers like npm or Yarn.
listed in
package.json
. It’s created when you runnpx create-react-app
ornpm install
. This folder can be quite large and is usually ignored by version control (as specified in.gitignore
). -
public
: The public folder:Public Folder: In web applications, the public folder is a directory that contains static assets that are directly served to the web browser without any processing. This typically includes HTML files, images, and other assets that don’t require server-side rendering or compilation.
contains static assets for your application.
-
index.html
: This is the single HTML file for your entire single-page application (SPA).Single Page Application (SPA): A web application that loads a single HTML page and dynamically updates the content within that page as the user interacts with the application. SPAs provide a more fluid and responsive user experience compared to traditional multi-page applications.
In React SPAs, you will typically only have one
index.html
file. The UI dynamically changes within this page, but it’s this single file that is served to the browser. You generally won’t modify this file extensively, mainly making adjustments in the<head>
section if needed. Crucially, within the<body>
tag, you’ll find a<div>
element with theid="root"
.<div id="root"></div>
This
<div>
is the root DOM node:Root DOM Node: The root DOM node is a specific HTML element in the
index.html
file that serves as the container where React will render and manage the entire user interface of your application. In Create React App, this is typically a<div>
element with theid="root"
.React will take control of this
<div>
at runtime and render your application’s UI inside it. -
manifest.json
,favicon.ico
,logo*.png
: These files are related to Progressive Web Apps (PWAs):Progressive Web App (PWA): A type of web application that is designed to provide a user experience similar to native mobile applications, but delivered through web technologies. PWAs offer features like offline capabilities, push notifications, and installability on users’ devices.
PWAs are beyond the scope of this beginner course.
-
robots.txt
: This file is used for search engine optimization (SEO):Search Engine Optimization (SEO): The practice of optimizing a website or web page to improve its visibility in search engine results pages (SERPs). This involves various techniques to make it easier for search engines to find, crawl, and index a website’s content.
and is not specific to React.
-
-
src
: The source folder:Source Folder: In software projects, the source folder (often named
src
orsource
) is the directory where the source code files of the application are stored. This includes JavaScript files, CSS files, and other assets that are essential for building the application’s logic and user interface.is where you will spend most of your development time. It contains the source code of your React application.
-
index.js
: This is the entry point of your React application.Entry Point: The entry point of an application is the starting point where the execution of the program begins. In a React application created with Create React App,
index.js
is the file that initializes the React application and renders the root component into the DOM.It’s the first JavaScript file that gets executed. Within
index.js
, you’ll find:- The root component, which is the
App
component (fromApp.js
). - The DOM element that React will control, identified by
id="root"
inindex.html
. React renders theApp
component into this root DOM node.
- The root component, which is the
-
App.js
: This file contains theApp
component:App Component: In React applications created with Create React App, the App component is the root component of the application. It serves as the starting point for building the user interface and typically contains or orchestrates other components to create the overall application structure.
which is the main component of your application. It’s responsible for the initial HTML displayed in the browser.
App.js
typically includes:- JSX: The code that defines the structure and content of the UI.
- CSS Import: An import statement to include styling from
App.css
. - Test File Import: Potentially, an import for
App.test.js
for unit testing. - Logo Import: An import for
logo.svg
if used in the component.
-
App.css
: Contains CSS styles specifically for theApp
component. -
App.test.js
: A file for writing unit tests:Unit Test: A type of software testing where individual units or components of a software application are tested in isolation. In React, unit tests typically focus on testing individual components to ensure they function correctly and produce the expected output.
for the
App
component. -
index.css
: Contains global CSS styles that are applied to the<body>
tag and are referenced inindex.js
. -
logo.svg
: The React logo in SVG format, often referenced in theApp
component. -
reportWebVitals.js
&setupTests.js
: These files are related to performance analytics and testing setup, respectively. As a beginner, you can generally ignore these initially.
-
Application Startup Flow
When you run npm start
, the following sequence of events occurs:
-
index.html
is served: Theindex.html
file from thepublic
folder is served to the browser. This file contains the root DOM node (<div id="root"></div>
). -
index.js
takes control: The browser executesindex.js
. This script uses the React DOM library to:- Identify the root DOM node in
index.html
. - Render the
App
component into this root DOM node.
- Identify the root DOM node in
-
App
component renders UI: TheApp
component, defined inApp.js
, contains the JSX that describes the UI. React renders this JSX into the root DOM node, making it visible in the browser.
React 18 Update in index.js
The transcript mentions a necessary update in index.js
for React 18 compatibility. Create React App might install version 18, but the default index.js
might still use an older API. To ensure you’re using React 18 features, make the following changes in src/index.js
:
import React from 'react';
// Comment out the following line:
// import ReactDOM from 'react-dom';
// Replace it with:
import { createRoot } from 'react-dom/client';
import App from './App';
import './index.css';
// Comment out:
// ReactDOM.render(
// <React.StrictMode>
// <App />
// </React.StrictMode>,
// document.getElementById('root')
// );
// Replace with:
const container = document.getElementById('root');
const root = createRoot(container); // Create a root.
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
This modification updates the root API to use createRoot
from react-dom/client
, enabling React 18 features in your application. If you are following this tutorial some time after the video’s publication, Create React App might have already been updated, and this step might not be necessary.
Components: The Building Blocks of React UI
React applications are built using components.
Component (in React): A component is a reusable and independent building block of a React user interface. It is a self-contained unit that encapsulates its own logic, styling, and rendering. Components can be composed together to create complex UIs.
Think of components as modular, reusable pieces of your UI. A website can be decomposed into sections like:
- Header
- Navigation Bar (Site Nav)
- Main Content
- Footer
Each of these sections can be represented as a React component. Components can be nested within each other to build complex UIs. The top-level component that encompasses the entire application is often called the root component, typically named App
in Create React App projects.
Components promote code reusability. For example, a navigation component can be reused for both the left and right side navigation, potentially with different content but the same UI structure.
Types of Components: Function vs. Class
In React, there are two main types of components:
-
Function Components: These are simpler and more modern. They are essentially JavaScript functions that return JSX (which we’ll discuss shortly) to describe the UI. Function components are the primary type used in modern React development and are the focus of this crash course.
-
Class Components: These are older, more complex components defined using JavaScript classes. While still functional, they are generally less favored for new development in 2022 and beyond. This crash course will primarily focus on function components.
Examining the App
Component
Let’s look at the default App
component in App.js
.
import logo from './logo.svg';
import './App.css';
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
export default App;
Key observations:
-
.js
Extension:App.js
is a JavaScript file, signifying it contains JavaScript code. -
JavaScript Function
App
: The code defines a JavaScript function namedApp
. This is a function component. -
JSX Return Value: The
App
function returns JSX (HTML-like syntax). This JSX describes the structure of the UI. In this case, it returns:- A wrapping
<div>
tag. - A
<header>
tag. - An
<img>
tag for the React logo. - A
<p>
(paragraph) tag with instructions. - An
<a>
(link) tag.
- A wrapping
-
export default App;
: The component is exported as the default export:Default Export: In JavaScript modules, a default export is the primary export from a module. Each module can have at most one default export. When importing a default export, you can choose any name for the import.
This allows
index.js
to import and use theApp
component.
Real-world applications can have numerous components, ranging from tens to thousands, especially in large applications like Facebook, which reportedly uses over 30,000 components.
Creating a Function Component: Greet
Component
Let’s create a simple function component to illustrate the concept. We’ll create a component named Greet
that displays the message “Hello Vishwas”.
-
Create
Greet.js
: Inside thesrc
folder, create a new folder named “components”. Within the “components” folder, create a new file namedGreet.js
. -
Define
Greet
Component: InGreet.js
, add the following code:import React from 'react'; // Function Component using function declaration function Greet() { return <h1>Hello Vishwas</h1>; } export default Greet;
Alternatively, you can use an arrow function:
Arrow Function: A concise syntax for writing functions in JavaScript, introduced in ES6 (ECMAScript 2015). Arrow functions are often more compact and have lexical
this
binding, which can simplify certain JavaScript patterns.import React from 'react'; // Function Component using arrow function const Greet = () => { return <h1>Hello Vishwas</h1>; } export default Greet;
-
Import and Use
Greet
inApp.js
:-
In
App.js
, remove the existing JSX within the main<div>
(keep the outer<div>
withclassName="App"
). -
At the top of
App.js
, import theGreet
component:import Greet from './components/Greet';
-
Within the
App
component’s JSX, add the<Greet>
component tag:function App() { return ( <div className="App"> <Greet /> </div> ); }
-
-
View in Browser: Save both
Greet.js
andApp.js
. In the browser, you should now see “Hello Vishwas” displayed. Your first custom function component is rendered!
Exporting and Importing Components: Default vs. Named Exports
-
Default Export (used in
Greet.js
):export default Greet;
- Allows you to import the component with any name in the importing file. For example, in
App.js
, we imported it asimport Greet from './components/Greet';
. We could have named itMyComponent
and used<MyComponent />
instead, and it would still work because it’s the default export.
- Allows you to import the component with any name in the importing file. For example, in
-
Named Export: Let’s modify
Greet.js
to use a named export:import React from 'react'; export const Greet = () => { // Notice 'export' keyword return <h1>Hello Vishwas</h1>; }
-
To import a named export, you must use the exact same name within curly braces in the import statement in
App.js
:import { Greet } from './components/Greet'; // Curly braces and 'Greet' name
-
If you try to import it with a different name without curly braces (like with default exports), it will result in an error.
-
This course will primarily use named exports for component examples, but understanding both default and named exports is crucial for working with React codebases.
JSX: JavaScript XML
JSX:
JSX (JavaScript XML): A syntax extension to JavaScript that allows you to write HTML-like code within JavaScript files. JSX is primarily used in React to describe the structure of user interfaces in a declarative manner. It gets transformed into regular JavaScript function calls by tools like Babel during the build process.
JSX is a core concept in React. It may look like HTML, but it’s a syntax extension to JavaScript. JSX allows you to embed HTML-like structures directly within your JavaScript code, making it easier to define the UI of your React components.
JSX Features and Differences from HTML
-
JavaScript Expressions: JSX allows you to embed JavaScript expressions within your HTML-like code using curly braces
{}
. For example:<div>{2 + 2}</div> {/* Renders '4' */}
You can evaluate expressions, call functions, and perform conditional logic within JSX using curly braces.
-
Attribute Naming Conventions: JSX has some differences in attribute naming compared to standard HTML:
-
class
becomesclassName
: In HTML, you useclass
to define CSS classes. In JSX, you must useclassName
becauseclass
is a reserved keyword in JavaScript.// HTML <div class="my-class"></div> // JSX <div className="my-class"></div>
-
for
becomeshtmlFor
: Similarly,for
attribute (used with<label>
) becomeshtmlFor
in JSX due tofor
being a JavaScript keyword.// HTML <label for="name">Name:</label> <input type="text" id="name" /> // JSX <label htmlFor="name">Name:</label> <input type="text" id="name" />
-
CamelCase Property Naming: JSX uses camelCase for HTML attribute names that are composed of multiple words. For example:
onclick
becomesonClick
tabindex
becomestabIndex
You will encounter these differences as you work with JSX.
-
React Elements: JSX Under the Hood
While JSX looks like HTML, React doesn’t directly work with HTML strings in the browser. Under the hood, JSX is transformed into React elements:
React Element: A React element is the smallest unit of a React application’s UI. It is a plain JavaScript object that describes a DOM node or another component. React elements are lightweight descriptions of what should be rendered on the screen.
When your React component returns JSX, it’s actually creating React elements. These elements are then processed by React DOM to efficiently update the actual DOM and render the UI in the browser.
For beginners, it’s sufficient to understand that JSX is a convenient syntax for writing UI structures, and React handles the underlying conversion to React elements and DOM updates.
Props: Passing Data to Components
Props, short for “properties”:
Props (Properties): In React, props are inputs passed down from parent components to child components. They are read-only objects that allow parent components to configure and control the behavior and appearance of their children. Props are a primary mechanism for data flow in React.
are a fundamental mechanism for passing data from parent components to child components. They make components dynamic and reusable.
Passing Props
To pass props to a component, you specify them as attributes when you use the component tag in JSX.
Let’s modify our Greet
component to accept a name
prop and display a personalized greeting.
-
Modify
Greet.js
to Accept Props:import React from 'react'; const Greet = (props) => { // Add 'props' parameter return ( <div> <h1>Hello {props.name}</h1> {/* Access 'name' prop */} </div> ); } export default Greet;
- We added a
props
parameter to theGreet
function component. - Inside the JSX, we use
{props.name}
to access the value of thename
prop.props
is an object, andprops.name
accesses the property named “name” within that object.
- We added a
-
Pass Props from
App.js
:import React from 'react'; import Greet from './components/Greet'; function App() { return ( <div className="App"> <Greet name="Bruce" /> {/* Pass 'name' prop with value "Bruce" */} <Greet name="Clark" /> {/* Pass 'name' prop with value "Clark" */} <Greet name="Diana" /> {/* Pass 'name' prop with value "Diana" */} </div> ); } export default App;
- In
App.js
, when we use the<Greet>
tag, we add attributes likename="Bruce"
,name="Clark"
, andname="Diana"
. These attributes become props passed to theGreet
component.
- In
-
View in Browser: Save and view in the browser. You should see:
Hello Bruce Hello Clark Hello Diana
The
Greet
component is now reusable. By passing differentname
props, we can greet different people using the same component.
Multiple Props
You can pass multiple props to a component. Let’s add a heroName
prop to our Greet
component.
-
Modify
Greet.js
to AcceptheroName
Prop:import React from 'react'; const Greet = (props) => { return ( <div> <h1>Hello {props.name} also known as {props.heroName}</h1> {/* Access 'heroName' prop */} </div> ); } export default Greet;
-
Pass
heroName
Props fromApp.js
:import React from 'react'; import Greet from './components/Greet'; function App() { return ( <div className="App"> <Greet name="Bruce" heroName="Batman" /> {/* Pass 'heroName' prop */} <Greet name="Clark" heroName="Superman" /> {/* Pass 'heroName' prop */} <Greet name="Diana" heroName="Wonder Woman" /> {/* Pass 'heroName' prop */} </div> ); } export default App;
-
View in Browser: Save and view in the browser. You should see:
Hello Bruce also known as Batman Hello Clark also known as Superman Hello Diana also known as Wonder Woman
props.children
: Rendering Dynamic Content
The props
object also has a special property called children
. props.children
:
props.children
: A special prop in React that represents the content passed between the opening and closing tags of a component. It allows a component to render dynamic content that is provided by its parent component.
allows you to pass content between the opening and closing tags of a component and render that content within the component.
-
Modify
Greet.js
to Renderprops.children
:import React from 'react'; const Greet = (props) => { return ( <div> <h1>Hello {props.name}</h1> {props.children} {/* Render 'children' prop */} </div> ); } export default Greet;
-
Pass Children Content in
App.js
:import React from 'react'; import Greet from './components/Greet'; function App() { return ( <div className="App"> <Greet name="Bruce" heroName="Batman"> <p>This is children props</p> {/* Content between tags becomes 'children' */} </Greet> <Greet name="Clark" heroName="Superman"> <button>Action</button> {/* Button as children */} </Greet> <Greet name="Diana" heroName="Wonder Woman" /> {/* No children content */} </div> ); } export default App;
- For the first two
<Greet>
components, we’ve added content between the opening and closing tags: a<p>
tag and a<button>
tag, respectively. For the third, there’s no content between the tags.
- For the first two
-
View in Browser: Save and view in the browser. You should see:
- For “Bruce/Batman”, the paragraph “This is children props” will be rendered below the greeting.
- For “Clark/Superman”, the “Action” button will be rendered below the greeting.
- For “Diana/Wonder Woman”, no additional content will be rendered below the greeting because no children were passed.
Immutability of Props
Props are immutable:
Immutable (in programming): Immutable data means that once an object is created, its state cannot be changed. Any operation that appears to modify an immutable object actually creates a new object with the modified state, leaving the original object unchanged.
This means you cannot modify the value of props within a component. Props are read-only from the perspective of the component receiving them. If you attempt to modify a prop, React will throw an error.
// Example of trying to modify a prop (will cause an error)
const Greet = (props) => {
props.name = "Vishwas"; // This is NOT allowed - will cause an error!
return (
<div>
<h1>Hello {props.name}</h1>
</div>
);
}
Props are controlled by the parent component that passes them down. Child components should not attempt to alter props.
State: Managing Component-Local Data
State:
State (in React): State is a JavaScript object that represents the internal data of a component. Unlike props, which are passed down from parent components, state is managed within the component itself. State is mutable, meaning its values can be changed, and when state changes, React automatically re-renders the component and its children to reflect the updated data in the UI.
is another crucial concept in React. It’s used to manage data that can change within a component over time, triggering UI updates.
Props vs. State: A Comparison
Feature | Props | State |
---|---|---|
Data Source | Passed down from parent components | Managed within the component itself |
Mutability | Immutable (read-only for child component) | Mutable (can be changed within the component) |
Purpose | Configure and control child components | Manage internal component data that can change |
Analogy | Function parameters | Variables declared within a function body |
Access | Accessed via props parameter | Managed using useState hook (function components) |
useState
Hook: Managing State in Function Components
The useState
hook:
useState
Hook: A built-in React Hook that allows function components to have state. It provides a way to declare state variables and update them, triggering re-renders when the state changes.
is the primary way to manage state in function components.
Let’s create a Message
component that uses state to display a message and change it when a button is clicked.
-
Create
Message.js
: In the “components” folder, create a new file namedMessage.js
. -
Define
Message
Component withuseState
:import React, { useState } from 'react'; // Import useState hook const Message = () => { // Declare state variable 'message' and setter function 'setMessage' const [message, setMessage] = useState('Welcome visitor'); // Initial state: 'Welcome visitor' return ( <div> <h1>{message}</h1> {/* Display state value */} <button onClick={() => setMessage('Thank you for subscribing')}> {/* Button to update state */} Subscribe </button> </div> ); } export default Message;
-
import { useState } from 'react';
: We import theuseState
hook from React. -
const [message, setMessage] = useState('Welcome visitor');
: This is how you use theuseState
hook:-
useState('Welcome visitor')
: We calluseState
with the initial value of our state variable, which is ‘Welcome visitor’. -
[message, setMessage] = ...
:useState
returns an array with two elements:message
: The current state variable itself (initialized to ‘Welcome visitor’).setMessage
: A function that you use to update themessage
state variable.
-
This syntax is called array destructuring:
Array Destructuring: A feature in JavaScript (ES6+) that allows you to unpack values from arrays or properties from objects into distinct variables. It provides a concise way to extract multiple values from an array or object in a single line of code.
-
-
<h1>{message}</h1>
: We display the current value of themessage
state variable in the<h1>
tag. -
<button onClick={() => setMessage('Thank you for subscribing')}>
:- We add a button with the text “Subscribe”.
onClick={...}
: We attach anonClick
event handler to the button.() => setMessage('Thank you for subscribing')
: This is an arrow function that will be executed when the button is clicked. Inside this function, we callsetMessage('Thank you for subscribing')
. This updates themessage
state variable to ‘Thank you for subscribing’.
-
-
Import and Use
Message
inApp.js
:import React from 'react'; import Message from './components/Message'; function App() { return ( <div className="App"> <Message /> </div> ); } export default App;
-
View in Browser: Save and view in the browser. You should see:
- Initially, “Welcome visitor” is displayed.
- When you click the “Subscribe” button, the text changes to “Thank you for subscribing”.
State Updates and Re-renders
When you call setMessage
to update the state, React does the following:
- Updates State: React updates the internal state of the
Message
component with the new value. - Re-renders Component: React automatically re-renders the
Message
component and its children. This means theMessage
function is executed again. - UI Update: During re-rendering, React detects that the
message
state variable has changed. It updates the DOM to reflect the new value ofmessage
in the UI.
This automatic re-rendering mechanism is a core feature of React, ensuring that the UI stays in sync with the component’s state.
Hooks: Hooking into React Features
Hooks:
Hooks (in React): Hooks are special functions in React that let you “hook into” React state and lifecycle features from within function components. They were introduced in React 16.8 to provide a way to use state and other React features in function components, which were previously only available in class components. Hooks are prefixed with
use
, such asuseState
,useEffect
, etc.
like useState
, are special functions that allow function components to access React features that were previously only available in class components (like state and lifecycle methods). Hooks start with the prefix use
(e.g., useState
, useEffect
).
React provides various built-in hooks for different purposes, including:
useState
: For managing state.useEffect
: For performing side effects (like API calls).useContext
: For accessing context values.useReducer
: For more complex state management.useRef
: For accessing DOM elements or persisting values across renders.useMemo
: For memoizing expensive calculations.useCallback
: For memoizing functions.useTransition
,useDeferredValue
: New hooks introduced in React 18 for performance optimizations.
For beginners, useState
and useEffect
are the most crucial hooks to learn initially.
Event Handling in React
Event Handling:
Event Handling (in programming): The process of responding to events that occur in a program or user interface. Events can be triggered by user interactions (like mouse clicks, keyboard presses), system events, or other program activities. Event handling involves detecting events and executing specific code (event handlers) to respond to them.
is essential for making web applications interactive. React provides a mechanism for handling events triggered by user interactions, such as clicks, mouseovers, form submissions, etc.
Let’s create a ClickHandler
component to demonstrate event handling.
-
Create
ClickHandler.js
: In the “components” folder, create a new file namedClickHandler.js
. -
Define
ClickHandler
Component with Event Handling:import React from 'react'; const ClickHandler = () => { function handleClick() { // Event handler function console.log('Button Clicked'); } return ( <div> <button onClick={handleClick}>Click</button> {/* Attach event handler */} </div> ); } export default ClickHandler;
-
function handleClick() { ... }
: We define an event handler function namedhandleClick
. This function will be executed when the button is clicked. In this example, it simply logs “Button Clicked” to the console. -
<button onClick={handleClick}>Click</button>
:onClick={handleClick}
: We attach thehandleClick
function as the event handler to the button’sonClick
event. Important: Notice that we pass the function referencehandleClick
, nothandleClick()
. We don’t call the function directly here. React will callhandleClick
when the button is clicked.
-
-
Import and Use
ClickHandler
inApp.js
:import React from 'react'; import ClickHandler from './components/ClickHandler'; function App() { return ( <div className="App"> <ClickHandler /> </div> ); } export default App;
-
View in Browser and Open Console: Save and view in the browser. Open the browser’s developer console (usually by pressing F12). When you click the “Click” button, you should see “Button Clicked” logged in the console.
Key Points about React Event Handling
-
CamelCase Event Names: React event names are camelCase:
CamelCase: A naming convention where compound words or phrases are written without spaces, with each word or abbreviation in the middle of the phrase beginning with a capital letter. For example,
firstName
,onClickHandler
,productDescription
.e.g.,
onClick
,onMouseOver
,onChange
. This is different from standard HTML event names (e.g.,onclick
,onmouseover
,onchange
). -
Function as Event Handler: You pass a JavaScript function as the event handler in JSX, not a string.
-
Event Object: Event handlers automatically receive an event object:
Event Object: In JavaScript and web development, an event object is an object that is automatically passed to an event handler function when an event occurs. It contains information and properties related to the specific event that took place, such as the target element, event type, mouse coordinates, keyboard keys pressed, etc.
as an argument. This event object contains information about the event that occurred (e.g., mouse coordinates, target element, etc.).
const ClickHandler = () => { function handleClick(event) { // Event object as parameter console.log('Button Clicked', event); // Log event object } return ( <div> <button onClick={handleClick}>Click</button> </div> ); }
-
Passing Arguments to Event Handlers: You can pass additional arguments to your event handler functions using arrow functions within the
onClick
attribute.const ClickHandler = () => { function handleClick(event, count = 1) { // 'count' parameter with default value console.log('Button Clicked', count, event); } return ( <div> <button onClick={(event) => handleClick(event, 5)}>Click 5</button> {/* Pass '5' as argument */} <button onClick={handleClick}>Click</button> {/* Default 'count' value */} </div> ); }
- For “Click 5” button, we use an arrow function
(event) => handleClick(event, 5)
inonClick
. This arrow function receives the event object and then callshandleClick
with the event and the additional argument5
. - For “Click” button, we directly pass
handleClick
as the handler, so it uses the defaultcount
value of1
.
- For “Click 5” button, we use an arrow function
Parent-Child Component Communication
React components often need to communicate with each other, particularly in parent-child relationships. We’ve already seen how parent components can pass data down to children using props. Now, let’s explore how child components can communicate back to parent components.
Child to Parent Communication using Props (Function as Prop)
Child components can communicate with parent components by calling functions provided by the parent as props.
Let’s create a ParentComponent
and a ChildComponent
. The ChildComponent
will have a button that, when clicked, will call a function defined in the ParentComponent
to display an alert.
-
Create
ParentComponent.js
: In the “components” folder, create a new file namedParentComponent.js
.import React from 'react'; import ChildComponent from './ChildComponent'; // Import ChildComponent const ParentComponent = () => { const greetParent = (childName) => { // Function in ParentComponent alert(`Hello Parent, ${childName}`); } return ( <ChildComponent greetHandler={greetParent} /> {/* Pass 'greetParent' as prop */} ); } export default ParentComponent;
const greetParent = (childName) => { ... }
: We define a functiongreetParent
in theParentComponent
. This function will be called by theChildComponent
. It takes achildName
argument and displays an alert.<ChildComponent greetHandler={greetParent} />
: We use theChildComponent
and pass thegreetParent
function as a prop namedgreetHandler
.
-
Create
ChildComponent.js
: In the “components” folder, create a new file namedChildComponent.js
.import React from 'react'; const ChildComponent = (props) => { // Accept 'props' return ( <div> <button onClick={() => props.greetHandler('child')}> {/* Call 'greetHandler' prop */} Greet Parent </button> </div> ); } export default ChildComponent;
const ChildComponent = (props) => { ... }
: TheChildComponent
acceptsprops
.<button onClick={() => props.greetHandler('child')}>
:onClick={() => ...}
: We attach anonClick
handler to the button.props.greetHandler('child')
: Inside the handler, we call thegreetHandler
function that was passed as a prop from the parent. We pass the string ‘child’ as an argument togreetHandler
.
-
Import and Use
ParentComponent
inApp.js
:import React from 'react'; import ParentComponent from './components/ParentComponent'; function App() { return ( <div className="App"> <ParentComponent /> </div> ); } export default App;
-
View in Browser: Save and view in the browser. You should see a button labeled “Greet Parent”. When you click this button:
- The
onClick
handler inChildComponent
is triggered. props.greetHandler('child')
is called, which executes thegreetParent
function inParentComponent
.- The alert “Hello Parent, child” is displayed.
- The
This demonstrates how a child component can trigger logic in its parent component by calling a function passed as a prop. This is a common pattern for child-to-parent communication in React.
Conditional Rendering
Conditional Rendering:
Conditional Rendering (in React): The process of displaying different UI elements or components based on certain conditions or states in a React application. It allows you to dynamically control what is rendered on the screen based on JavaScript logic.
is a technique to display different content in your React UI based on conditions. React’s conditional rendering works similarly to conditional logic in JavaScript.
Let’s create a UserGreeting
component to demonstrate conditional rendering. We’ll display “Welcome Vishwas” if the user is logged in, and “Welcome Guest” otherwise.
-
Create
UserGreeting.js
: In the “components” folder, create a new file namedUserGreeting.js
. -
Define
UserGreeting
Component with Conditional Rendering:import React from 'react'; const UserGreeting = () => { const isLoggedIn = true; // Condition: User logged in (change to 'false' to test) return ( <div> <div>Welcome {isLoggedIn ? 'Vishwas' : 'Guest'}</div> {/* Ternary operator */} </div> ); } export default UserGreeting;
-
const isLoggedIn = true;
: We define a boolean variableisLoggedIn
to represent the login status. You can change this tofalse
to test the other condition. -
<div>Welcome {isLoggedIn ? 'Vishwas' : 'Guest'}</div>
: We use the ternary operator:Ternary Operator: A concise conditional operator in JavaScript (and many other languages) that provides a shorthand for writing simple
if-else
statements. It has the syntaxcondition ? expressionIfTrue : expressionIfFalse
.(condition ? valueIfTrue : valueIfFalse)
to conditionally render the greeting:- If
isLoggedIn
istrue
, it renders ‘Vishwas’. - If
isLoggedIn
isfalse
, it renders ‘Guest’.
- If
-
-
Import and Use
UserGreeting
inApp.js
:import React from 'react'; import UserGreeting from './components/UserGreeting'; function App() { return ( <div className="App"> <UserGreeting /> </div> ); } export default App;
-
View in Browser: Save and view in the browser.
- If
isLoggedIn
istrue
inUserGreeting.js
, you’ll see “Welcome Vishwas”. - If
isLoggedIn
isfalse
, you’ll see “Welcome Guest”.
- If
Short-Circuit Operator for Conditional Rendering
Another approach for conditional rendering is using the short-circuit operator:
Short-Circuit Operator: In JavaScript (and many other languages), short-circuit operators are logical operators (
&&
- AND,||
- OR) that exhibit “short-circuiting” behavior. This means that the evaluation of the expression stops as soon as the result is determined. For example, incondition1 && condition2
, ifcondition1
is false,condition2
is not evaluated because the result is already known to be false.
The short-circuit &&
operator is useful when you want to render something only if a condition is true, otherwise render nothing.
Let’s modify UserGreeting.js
to use the short-circuit operator.
import React from 'react';
const UserGreeting = () => {
const isLoggedIn = true;
return (
<div>
<div>Welcome</div>
{isLoggedIn && <div>Vishwas</div>} {/* Short-circuit operator */}
</div>
);
}
{isLoggedIn && <div>Vishwas</div>}
:isLoggedIn && ...
: IfisLoggedIn
istrue
, the expression on the right (<div>Vishwas</div>
) is evaluated and rendered.- If
isLoggedIn
isfalse
, the expression on the right is not evaluated (short-circuited), and nothing is rendered in place of this expression.
If isLoggedIn
is true
, you’ll see “Welcome” and “Vishwas” rendered. If isLoggedIn
is false
, you’ll only see “Welcome”.
List Rendering
List Rendering:
List Rendering (in React): The process of dynamically generating a list of UI elements or components based on an array of data. React uses the
map
method to iterate over arrays and create a corresponding component or element for each item in the array.
is a common task in web development. You often need to display lists of items, like names, products, or articles. In React, you use JavaScript’s map
method to efficiently render lists.
Let’s create a NameList
component to render a list of names.
-
Create
NameList.js
: In the “components” folder, create a new file namedNameList.js
. -
Define
NameList
Component with List Rendering:import React from 'react'; const NameList = () => { const names = ['Bruce', 'Clark', 'Diana']; // Array of names return ( <div> {names.map(name => ( // Map over 'names' array <h2 key={name}>{name}</h2> // Render <h2> for each name ))} </div> ); } export default NameList;
const names = ['Bruce', 'Clark', 'Diana'];
: We define an array of names.{names.map(name => ...)}
:-
names.map(...)
: We use themap
method on thenames
array.map
Method (JavaScript Array): A built-in method for JavaScript arrays that creates a new array by calling a provided function on every element in the original array. It transforms each element of the array based on the function and returns a new array of the transformed elements. -
name => (...)
: For eachname
in thenames
array, the arrow functionname => (...)
is executed. -
<h2 key={name}>{name}</h2>
: Inside the arrow function, we return an<h2>
tag. Thename
is used as the content of the<h2>
tag. -
key={name}
:key
prop:key
Prop (in React List Rendering): A special prop that should be provided when rendering lists of elements or components in React. Thekey
prop helps React identify which items in the list have changed, been added, or been removed. Keys should be unique and stable identifiers for each item in the list.is crucial when rendering lists in React. It helps React efficiently update lists, especially when items are added, removed, or reordered. For this simple example, we use the
name
itself as thekey
because names are unique in this list. Important: Keys must be unique within the list.
-
-
Import and Use
NameList
inApp.js
:import React from 'react'; import NameList from './components/NameList'; function App() { return ( <div className="App"> <NameList /> </div> ); } export default App;
-
View in Browser: Save and view in the browser. You should see the list of names rendered as
<h2>
headings:Bruce Clark Diana
Key Prop Importance
While the above example works, if you inspect the browser console, you might see a warning: “Each child in a list should have a unique “key” prop.” This warning highlights the importance of the key
prop.
The key
prop helps React:
- Efficiently Update Lists: React uses keys to identify which list items have changed, been added, or removed. This allows React to update the DOM more efficiently when lists change.
- Prevent Bugs: Keys can help prevent unexpected behavior and bugs, especially when dealing with lists that involve sorting, filtering, or dynamic updates.
When rendering lists of objects, it’s common to use a unique ID property from each object as the key
. For example, if your data is an array of objects like:
const persons = [
{ id: 1, name: 'Bruce', age: 30 },
{ id: 2, name: 'Clark', age: 32 },
{ id: 3, name: 'Diana', age: 28 },
];
You would use item.id
as the key
prop:
{persons.map(person => (
<h2 key={person.id}>{person.name}</h2>
))}
Styling and CSS in React
Styling is a fundamental aspect of web development. React offers several ways to style your components:
- Regular CSS Stylesheets: Traditional CSS stylesheets can be imported and used in React components.
- Inline Styling: Styles can be applied directly to JSX elements as inline styles.
- CSS Modules: CSS Modules scope CSS classes locally to components, preventing naming conflicts and improving CSS organization.
- CSS-in-JS Libraries: Libraries like styled-components or Emotion allow you to write CSS directly within your JavaScript code.
This crash course will cover the first three approaches.
1. Regular CSS Stylesheets
Let’s create a Stylesheet
component and style it using a regular CSS stylesheet.
-
Create
Stylesheet.js
: In the “components” folder, create a new file namedStylesheet.js
.import React from 'react'; import './MyStyles.css'; // Import CSS stylesheet const Stylesheet = () => { return ( <div> <h1 className='primary'>Stylesheets</h1> {/* Apply CSS class */} </div> ); } export default Stylesheet;
import './MyStyles.css';
: We import the CSS stylesheet namedMyStyles.css
(which we’ll create next).<h1 className='primary'>Stylesheets</h1>
: We useclassName='primary'
to apply the CSS class namedprimary
to the<h1>
element.
-
Create
MyStyles.css
: In the “components” folder, create a new file namedMyStyles.css
..primary { color: orange; }
- We define a CSS class named
primary
that sets the text color to orange.
- We define a CSS class named
-
Import and Use
Stylesheet
inApp.js
:import React from 'react'; import Stylesheet from './components/Stylesheet'; function App() { return ( <div className="App"> <Stylesheet /> </div> ); } export default App;
-
View in Browser: Save and view in the browser. You should see “Stylesheets” text rendered in orange color.
2. Inline Styling
Inline styles are applied directly to JSX elements using the style
attribute. Styles are provided as JavaScript objects.
-
Create
Inline.js
: In the “components” folder, create a new file namedInline.js
.import React from 'react'; const Inline = () => { const headingStyle = { // Style object fontSize: '72px', color: 'blue' } return ( <div> <h1 style={headingStyle}>Inline</h1> {/* Apply inline style */} </div> ); } export default Inline;
const headingStyle = { ... };
: We create a JavaScript objectheadingStyle
to define the styles. Important: CSS property names in inline styles are camelCase (e.g.,fontSize
,color
). Values are typically strings.<h1 style={headingStyle}>Inline</h1>
: We apply theheadingStyle
object to thestyle
attribute of the<h1>
element.
-
Import and Use
Inline
inApp.js
:import React from 'react'; import Inline from './components/Inline'; function App() { return ( <div className="App"> <Inline /> </div> ); } export default App;
-
View in Browser: Save and view in the browser. You should see “Inline” text rendered in blue color and a large font size.
3. CSS Modules
CSS Modules are a technique to scope CSS classes locally to components. This prevents CSS class name collisions and makes CSS more modular and maintainable in larger projects.
-
Create CSS Module Stylesheet: In the
src
folder (not “components”), create a new file namedAppStyles.module.css
. Important: The.module.css
extension is crucial for CSS Modules..error { color: red; } .success { color: green; }
- We define two CSS classes:
error
(red color) andsuccess
(green color).
- We define two CSS classes:
-
Create Regular CSS Stylesheet: In the
src
folder, create a regular CSS stylesheet namedAppStyles.css
..error { color: purple; /* Different color for regular CSS */ }
- We also define an
error
class in the regular stylesheet, but with a different color (purple).
- We also define an
-
Modify
App.js
to Use CSS Modules and Regular CSS:import React from 'react'; import './AppStyles.css'; // Import regular CSS stylesheet import styles from './AppStyles.module.css'; // Import CSS Module stylesheet function App() { return ( <div className="App"> <h1 className="error">Error</h1> {/* Class from regular CSS */} <h1 className={styles.success}>Success</h1> {/* Class from CSS Module */} </div> ); } export default App;
import './AppStyles.css';
: We import the regular CSS stylesheet as usual.import styles from './AppStyles.module.css';
: We import the CSS Module stylesheet. Important: When importing a CSS Module, you typically import it as a JavaScript object (e.g.,styles
).<h1 className="error">Error</h1>
: To use theerror
class from the regular stylesheet, we apply it directly usingclassName="error"
.<h1 className={styles.success}>Success</h1>
: To use thesuccess
class from the CSS Module, we access it as a property of thestyles
object:styles.success
.
-
View in Browser: Save and view in the browser. You should see:
- “Error” text rendered in purple color (from
AppStyles.css
). - ”Success” text rendered in green color (from
AppStyles.module.css
).
- “Error” text rendered in purple color (from
CSS Modules: Local Scoping Advantage
One of the main advantages of CSS Modules is that CSS classes are locally scoped:
Locally Scoped CSS (CSS Modules): A technique where CSS class names are transformed during the build process to be unique to the component they are used in. This prevents CSS naming collisions and ensures that styles defined for one component do not accidentally affect other components. CSS Modules typically use a naming convention or build tools to generate these unique class names.
by default. This means that class names defined in a CSS Module are only applied to the component that imports that module. They don’t “leak out” and affect other components, preventing CSS conflicts.
For example, if you try to use styles.success
class in another component (like Inline.js
), it won’t work because styles
object is only available within App.js
component where it’s imported. This local scoping improves CSS organization and maintainability, especially in larger applications.
Working with Forms in React
Forms are essential for user input in web applications. React provides mechanisms to manage form data and handle form submissions.
Let’s create a Form
component to demonstrate basic form handling. We’ll create a form with a username input field and a submit button.
-
Create
Form.js
: In the “components” folder, create a new file namedForm.js
.import React, { useState } from 'react'; // Import useState hook const Form = () => { const [username, setUsername] = useState(''); // State for username input const handleUsernameChange = (event) => { // Event handler for input change setUsername(event.target.value); // Update username state } const handleSubmit = (event) => { // Event handler for form submit event.preventDefault(); // Prevent default form submission alert(`Form data is ${username}`); // Display form data (username) } return ( <form onSubmit={handleSubmit}> {/* Attach submit handler to form */} <div> <label>Username: </label> <input type="text" value={username} onChange={handleUsernameChange} /> {/* Input field */} </div> <button type="submit">Submit</button> {/* Submit button */} </form> ); } export default Form;
import React, { useState } from 'react';
: ImportuseState
hook.const [username, setUsername] = useState('');
: Create a state variableusername
to store the input value. Initialize it to an empty string.const handleUsernameChange = (event) => { ... };
: Define an event handlerhandleUsernameChange
for theonChange
event of the input field:setUsername(event.target.value);
: Update theusername
state with the current value of the input field (event.target.value
).
const handleSubmit = (event) => { ... };
: Define an event handlerhandleSubmit
for theonSubmit
event of the form:-
event.preventDefault();
:event.preventDefault()
:event.preventDefault()
: A method in JavaScript that is called on an event object to prevent the browser’s default behavior associated with that event. For example, for form submission events (onSubmit
),event.preventDefault()
prevents the default action of submitting the form to a new page and refreshing the browser.prevents the default HTML form submission behavior, which would typically cause the page to refresh or navigate to a new page. In React, we usually handle form submissions using JavaScript.
-
alert(
Form data is ${username});
: Display an alert with the current value of theusername
state.
-
<form onSubmit={handleSubmit}>
: Attach thehandleSubmit
function to theonSubmit
event of the<form>
element.<input type="text" value={username} onChange={handleUsernameChange} />
: Create an input field of type “text”:-
value={username}
: Bind thevalue
attribute of the input field to theusername
state variable. This makes the input field a controlled component:Controlled Component (in React Forms): A form element (like
<input>
,<textarea>
,<select>
) in React where its value is controlled by React state. This means that the value of the form element is always derived from and updated through React state, providing a single source of truth and enabling React to manage the form element’s behavior. -
onChange={handleUsernameChange}
: Attach thehandleUsernameChange
function to theonChange
event. This ensures that whenever the user types into the input field, thehandleUsernameChange
function is called, updating theusername
state, and React re-renders the input field with the new value.
-
<button type="submit">Submit</button>
: Create a submit button.
-
Import and Use
Form
inApp.js
:import React from 'react'; import Form from './components/Form'; function App() { return ( <div className="App"> <Form /> </div> ); } export default App;
-
View in Browser: Save and view in the browser. You should see the form with the username input and submit button.
- Type a username into the input field.
- Click the “Submit” button.
- You should see an alert box displaying “Form data is [your entered username]“. The page should not refresh due to
event.preventDefault()
.
HTTP Requests in React
Web applications often need to interact with APIs to fetch data or send data to servers. React provides mechanisms to make HTTP requests. We’ll demonstrate how to make GET and POST requests using the Fetch API:
Fetch API: A modern JavaScript interface for making network requests (like HTTP requests) in web browsers. It provides a more powerful and flexible alternative to the older
XMLHttpRequest
(XHR) object. The Fetch API is promise-based, making it easier to handle asynchronous operations like network requests.
GET Request: Fetching Data
Let’s create a PostList
component to fetch a list of posts from a public API (JSONPlaceholder) and display them.
-
Create
PostList.js
: In the “components” folder, create a new file namedPostList.js
.import React, { useState, useEffect } from 'react'; // Import useState and useEffect hooks const PostList = () => { const [posts, setPosts] = useState([]); // State to store posts useEffect(() => { // useEffect hook for side effects (API call) fetch('https://jsonplaceholder.typicode.com/posts') // Fetch API GET request .then(response => response.json()) // Convert response to JSON .then(data => { setPosts(data); // Update posts state with fetched data }) .catch(error => { console.error('Error fetching data:', error); // Handle errors }); }, []); // Empty dependency array: Run effect only once on mount return ( <div> <h1>Post List</h1> <ul> {posts.map(post => ( // Map over posts array to render list items <li key={post.id}>{post.title}</li> // Render <li> for each post title ))} </ul> </div> ); } export default PostList;
-
import React, { useState, useEffect } from 'react';
: ImportuseState
anduseEffect
hook:useEffect
Hook: A built-in React Hook that allows function components to perform side effects. Side effects are operations that interact with the outside world or have effects beyond the component’s rendering logic, such as data fetching, DOM manipulation, timers, and logging. TheuseEffect
hook is used to manage these side effects in function components. -
const [posts, setPosts] = useState([]);
: Create a state variableposts
to store the fetched post data. Initialize it as an empty array. -
useEffect(() => { ... }, []);
: Use theuseEffect
hook to perform the data fetching side effect:-
fetch('https://jsonplaceholder.typicode.com/posts')
: Use the Fetch API to make a GET request to the API endpoint to fetch posts. -
.then(response => response.json()): After the request is successful, the
fetch
API returns a promise:Promise (in JavaScript): An object that represents the eventual result of an asynchronous operation. Promises are used to handle asynchronous operations in a more structured and manageable way, especially for operations that may take time to complete, like network requests or file I/O. Promises can be in one of three states: pending, fulfilled (resolved), or rejected.
We use
.then()
to handle the resolved promise. We convert the response body to JSON usingresponse.json()
, which also returns a promise. -
.then(data => { setPosts(data); }): In the next
.then()
block, we receive the parsed JSON data (an array of posts). We callsetPosts(data)
to update theposts
state with the fetched data. -
.catch(error => { … }): Use
.catch()
to handle any errors that occur during the fetch process (e.g., network errors). Log the error to the console. -
[]
(dependency array): The empty dependency array[]
as the second argument touseEffect
tells React to run this effect only once after the initial render (component mount). This is appropriate for fetching data that you only need to load once when the component loads.
-
-
<ul> {posts.map(post => ...)} </ul>
: Render an unordered list (<ul>
) to display the posts:posts.map(post => ...)
: Map over theposts
array.<li key={post.id}>{post.title}</li>
: For eachpost
object, render a list item (<li>
) displaying thepost.title
. Usepost.id
as thekey
prop.
-
-
Import and Use
PostList
inApp.js
:import React from 'react'; import PostList from './components/PostList'; function App() { return ( <div className="App"> <PostList /> </div> ); } export default App;
-
View in Browser: Save and view in the browser. You should see a heading “Post List” followed by a list of post titles fetched from the API.
POST Request: Sending Data
Let’s create a PostForm
component to create a new post by sending data to the API using a POST request.
-
Create
PostForm.js
: In the “components” folder, create a new file namedPostForm.js
.import React, { useState } from 'react'; // Import useState hook const PostForm = () => { const [userId, setUserId] = useState(''); // State for userId input const [title, setTitle] = useState(''); // State for title input const [body, setBody] = useState(''); // State for body input const handleUserIdChange = (event) => { setUserId(event.target.value); }; const handleTitleChange = (event) => { setTitle(event.target.value); }; const handleBodyChange = (event) => { setBody(event.target.value); }; const handleSubmit = (event) => { // Form submit handler event.preventDefault(); // Prevent default submit fetch('https://jsonplaceholder.typicode.com/posts', { // Fetch API POST request method: 'POST', // Specify POST method body: JSON.stringify({ // Convert data to JSON string title: title, body: body, userId: userId }), headers: { // Set headers for JSON content 'Content-type': 'application/json; charset=UTF-8', }, }) .then(response => response.json()) // Convert response to JSON .then(json => console.log(json)); // Log response JSON to console } return ( <form onSubmit={handleSubmit}> {/* Form with submit handler */} <div> <input type="text" placeholder="User ID" value={userId} onChange={handleUserIdChange} /> </div> <div> <input type="text" placeholder="Title" value={title} onChange={handleTitleChange} /> </div> <div> <input type="text" placeholder="Body" value={body} onChange={handleBodyChange} /> </div> <button type="submit">Submit</button> {/* Submit button */} </form> ); } export default PostForm;
- State for Input Fields: We create state variables
userId
,title
, andbody
to manage the values of the input fields. - Event Handlers for Input Changes:
handleUserIdChange
,handleTitleChange
, andhandleBodyChange
update the corresponding state variables when the input field values change. handleSubmit
(Form Submit Handler):event.preventDefault();
: Prevent default form submission.fetch('https://jsonplaceholder.typicode.com/posts', { ... })
: Use the Fetch API to make a POST request to the API endpoint.method: 'POST'
: Specify the HTTP method asPOST
.body: JSON.stringify({ ... })
: Set the request body. We useJSON.stringify()
to convert the JavaScript object containingtitle
,body
, anduserId
to a JSON string, which is the format expected by the API for POST requests.headers: { 'Content-type': 'application/json; charset=UTF-8', }
: Set theContent-type
header toapplication/json; charset=UTF-8
. This tells the server that we are sending JSON data in the request body.
- .then(response => response.json()): Convert the response body to JSON.
- .then(json => console.log(json)): Log the JSON response to the console. The API typically returns the created post object in the response.
- State for Input Fields: We create state variables
-
Import and Use
PostForm
inApp.js
:import React from 'react'; import PostForm from './components/PostForm'; function App() { return ( <div className="App"> <PostForm /> </div> ); } export default App;
-
View in Browser and Open Console: Save and view in the browser. You should see the form with input fields for User ID, Title, and Body, and a Submit button.
- Fill in the input fields with values.
- Click the “Submit” button.
- Open the browser’s developer console. You should see the JSON response logged to the console. This response typically includes the data you sent in the POST request along with a unique
id
generated by the API.
React 18 Feature: useTransition
Hook for Performance Optimization
useTransition
Hook:
useTransition
Hook: A React Hook introduced in React 18 that allows you to mark certain state updates as non-urgent or “transitions.” Transitions help improve the perceived performance of applications by prioritizing urgent updates (like user input) over less urgent updates (like complex UI re-renders). This can prevent UI blocking and make applications feel more responsive, especially during heavy operations.
is a new hook introduced in React 18 primarily focused on performance optimization. It helps improve the responsiveness of your React applications, especially when dealing with heavy or slow UI updates.
Let’s demonstrate useTransition
with an example of filtering a large list of names.
-
Create
data.json
: In the “components” folder, create a new file nameddata.json
. Paste in a JSON array of 1000 names (you can generate dummy data using online tools like Macaroon). Each object in the array should haveid
,firstName
, andlastName
properties. -
Modify
App.js
to Implement List Filtering withuseTransition
:import React, { useState, useTransition } from 'react'; // Import useTransition hook import names from './components/data.json'; // Import data.json function App() { const [query, setQuery] = useState(''); // State for filter query const [inputValue, setInputValue] = useState(''); // Separate state for input value const [isPending, startTransition] = useTransition(); // useTransition hook const filteredNames = names.filter(item => { // Filter names based on query return query === "" ? true : item.firstName.toLowerCase().includes(query.toLowerCase()) || item.lastName.toLowerCase().includes(query.toLowerCase()); }); const handleChange = (event) => { // Input change handler setInputValue(event.target.value); // Update input value immediately startTransition(() => { // Mark filter update as transition setQuery(event.target.value); // Update filter query (non-urgent) }); }; return ( <div className="App"> <input type="text" value={inputValue} onChange={handleChange} placeholder="Filter names..." /> {isPending ? <p>Updating list...</p> : null} {/* Show "Updating list..." during transition */} {filteredNames.map(item => ( // Render filtered list <p key={item.id}>{item.firstName} {item.lastName}</p> ))} </div> ); } export default App;
import React, { useState, useTransition } from 'react';
: ImportuseTransition
hook.import names from './components/data.json';
: Import thedata.json
file containing the list of names.const [query, setQuery] = useState('');
: State variablequery
to store the filter query text.const [inputValue, setInputValue] = useState('');
: State variableinputValue
to store the current value of the input field. We use a separate state for the input value to ensure immediate input updates are always urgent.const [isPending, startTransition] = useTransition();
: CalluseTransition()
:isPending
: A boolean state variable that istrue
while a transition is pending (in progress) andfalse
otherwise.startTransition
: A function that you use to mark state updates as transitions.
const filteredNames = names.filter(...)
: Filter thenames
array based on thequery
text.const handleChange = (event) => { ... };
: Input change handler:setInputValue(event.target.value);
: Immediately updateinputValue
state with the input value. This is considered an urgent update because it’s directly related to user input.startTransition(() => { setQuery(event.target.value); });
: Mark the update toquery
state as a transition (non-urgent update):startTransition(() => { ... });
: CallstartTransition()
and pass a callback function as an argument.setQuery(event.target.value);
: Inside the callback, update thequery
state. React will treat this state update as a transition.
{isPending ? <p>Updating list...</p> : null}
: Conditionally render “Updating list…” paragraph whileisPending
istrue
(during the transition).{filteredNames.map(item => ...)}
: Render the filtered list of names.
-
Test Performance with CPU Throttling:
- Open your browser’s developer tools (F12).
- Go to the “Performance” tab.
- In the “CPU” dropdown, select “6x slowdown” (or similar CPU throttling option). This simulates running your application on a slower device.
- Type in the input field to filter the list.
- Observe the behavior:
- Without
useTransition
(if you removestartTransition
): You might notice a lag when typing, especially when deleting text. The input field and the list update might feel sluggish and happen at the same time because all updates are treated as urgent. - With
useTransition
: You should notice that the input field text updates immediately and smoothly as you type. The list filtering and re-render might happen with a slight delay (transition), and you’ll see the “Updating list…” text briefly. This is becauseuseTransition
prioritizes the urgent input update, making the UI feel more responsive even during the potentially slower list filtering operation.
- Without
useTransition
Benefits
- Improved Perceived Performance:
useTransition
helps make applications feel more responsive by prioritizing urgent updates (like input) and deferring less urgent updates (like complex re-renders). - Non-Blocking UI: Transitions prevent heavy updates from blocking the main thread, ensuring that the UI remains interactive and doesn’t become frozen or laggy during these operations.
- User Experience Enhancement: By making applications feel snappier and more responsive,
useTransition
contributes to a better overall user experience.
useTransition
is particularly useful in scenarios where you have:
- Heavy UI updates that can be computationally expensive (like complex filtering, large lists, animations).
- User interactions that need to feel immediate and responsive (like typing in input fields, clicking buttons).
Next Steps in Your React Journey
Congratulations on completing this React Fundamentals Crash Course! You now have a strong foundation in React’s core concepts. To continue your learning and become a proficient React developer, consider the following next steps:
-
React Roadmap: Review a React roadmap to get a broader understanding of the React ecosystem and the various topics and technologies you can explore. Consider watching a video or reading an article on a current React roadmap (e.g., “React Roadmap for 2023/2024”).
-
React Playlist/Tutorials: Dive deeper into React concepts with comprehensive React playlists or tutorials. Look for resources that cover:
- Class components (for understanding legacy code and advanced concepts).
- Advanced hooks (e.g.,
useContext
,useReducer
,useRef
,useMemo
,useCallback
). - Component re-rendering and optimization techniques.
- TypeScript with React (for type safety and improved code quality).
-
Explore React Libraries: Start learning and using popular React libraries to enhance your development capabilities:
- React Query: For efficient data fetching, caching, and state management for API requests.
- UI Component Libraries: Explore UI component libraries like Material UI, Chakra UI, or Mantine to quickly build user interfaces with pre-built, customizable components.
- Form Libraries: For complex form management, consider using libraries like Formik or React Hook Form.
- Next.js: Learn Next.js, a popular React framework for production-ready applications. Next.js provides features like server-side rendering, routing, and optimized build processes, making it ideal for building scalable and performant React applications.
- React Router: For navigation and routing in single-page React applications, learn React Router.
-
Practice and Build Projects: The best way to learn React is by building projects. Start with small projects and gradually increase complexity. Practice the concepts you’ve learned and experiment with different libraries and techniques.
-
Stay Updated: The React ecosystem is constantly evolving. Stay updated with new features, best practices, and library updates by following React blogs, communities, and official React documentation.
By consistently learning, practicing, and building projects, you will solidify your React skills and become a proficient front-end developer. Remember to leverage the vast resources available in the React community and explore the areas that interest you most. Good luck on your React journey!