YouTube Courses - Learn Smarter

YouTube-Courses.site transforms YouTube videos and playlists into structured courses, making learning more efficient and organized.

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:

  1. 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.

  2. 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.
  3. 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.

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:

  1. Open Integrated Terminal: In VS Code, open the integrated terminal by selecting View > Terminal.

  2. 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.

  3. Navigate to Project Folder: Once the command completes, navigate into the newly created project folder:

    cd react-demo
  4. 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 the package.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.”

  5. Modify App.js: In VS Code, expand the “src” folder in your project and open the App.js file. Locate the text within the return statement and change it to “Hello World”. Save the file (Ctrl+S or Cmd+S).

  6. 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 and react-dom (version 18 in this case). These are essential for building React applications.

    • Scripts: Defines commands you can run using npm, such as start (to run the development server), build (to create a production build), and test (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 or yarn.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 run npx create-react-app or npm 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 the id="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 the id="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 or source) 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 (from App.js).
      • The DOM element that React will control, identified by id="root" in index.html. React renders the App component into this root DOM node.
    • App.js: This file contains the App 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 the App 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 in index.js.

    • logo.svg: The React logo in SVG format, often referenced in the App 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:

  1. index.html is served: The index.html file from the public folder is served to the browser. This file contains the root DOM node (<div id="root"></div>).

  2. index.js takes control: The browser executes index.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.
  3. App component renders UI: The App component, defined in App.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:

  1. 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.

  2. 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 named App. 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.
  • 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 the App 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”.

  1. Create Greet.js: Inside the src folder, create a new folder named “components”. Within the “components” folder, create a new file named Greet.js.

  2. Define Greet Component: In Greet.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;
  3. Import and Use Greet in App.js:

    • In App.js, remove the existing JSX within the main <div> (keep the outer <div> with className="App").

    • At the top of App.js, import the Greet 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>
        );
      }
  4. View in Browser: Save both Greet.js and App.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 as import Greet from './components/Greet';. We could have named it MyComponent and used <MyComponent /> instead, and it would still work because it’s the default export.
  • 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 becomes className: In HTML, you use class to define CSS classes. In JSX, you must use className because class is a reserved keyword in JavaScript.

      // HTML
      <div class="my-class"></div>
      
      // JSX
      <div className="my-class"></div>
    • for becomes htmlFor: Similarly, for attribute (used with <label>) becomes htmlFor in JSX due to for 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 becomes onClick
      • tabindex becomes tabIndex

    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.

  1. 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 the Greet function component.
    • Inside the JSX, we use {props.name} to access the value of the name prop. props is an object, and props.name accesses the property named “name” within that object.
  2. 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 like name="Bruce", name="Clark", and name="Diana". These attributes become props passed to the Greet component.
  3. 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 different name 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.

  1. Modify Greet.js to Accept heroName 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;
  2. Pass heroName Props from App.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;
  3. 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.

  1. Modify Greet.js to Render props.children:

    import React from 'react';
    
    const Greet = (props) => {
      return (
        <div>
          <h1>Hello {props.name}</h1>
          {props.children} {/* Render 'children' prop */}
        </div>
      );
    }
    
    export default Greet;
  2. 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.
  3. 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

FeaturePropsState
Data SourcePassed down from parent componentsManaged within the component itself
MutabilityImmutable (read-only for child component)Mutable (can be changed within the component)
PurposeConfigure and control child componentsManage internal component data that can change
AnalogyFunction parametersVariables declared within a function body
AccessAccessed via props parameterManaged 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.

  1. Create Message.js: In the “components” folder, create a new file named Message.js.

  2. Define Message Component with useState:

    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 the useState hook from React.

    • const [message, setMessage] = useState('Welcome visitor');: This is how you use the useState hook:

      • useState('Welcome visitor'): We call useState 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 the message 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 the message state variable in the <h1> tag.

    • <button onClick={() => setMessage('Thank you for subscribing')}>:

      • We add a button with the text “Subscribe”.
      • onClick={...}: We attach an onClick 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 call setMessage('Thank you for subscribing'). This updates the message state variable to ‘Thank you for subscribing’.
  3. Import and Use Message in App.js:

    import React from 'react';
    import Message from './components/Message';
    
    function App() {
      return (
        <div className="App">
          <Message />
        </div>
      );
    }
    
    export default App;
  4. 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:

  1. Updates State: React updates the internal state of the Message component with the new value.
  2. Re-renders Component: React automatically re-renders the Message component and its children. This means the Message function is executed again.
  3. UI Update: During re-rendering, React detects that the message state variable has changed. It updates the DOM to reflect the new value of message 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 as useState, 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.

  1. Create ClickHandler.js: In the “components” folder, create a new file named ClickHandler.js.

  2. 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 named handleClick. 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 the handleClick function as the event handler to the button’s onClick event. Important: Notice that we pass the function reference handleClick, not handleClick(). We don’t call the function directly here. React will call handleClick when the button is clicked.
  3. Import and Use ClickHandler in App.js:

    import React from 'react';
    import ClickHandler from './components/ClickHandler';
    
    function App() {
      return (
        <div className="App">
          <ClickHandler />
        </div>
      );
    }
    
    export default App;
  4. 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) in onClick. This arrow function receives the event object and then calls handleClick with the event and the additional argument 5.
    • For “Click” button, we directly pass handleClick as the handler, so it uses the default count value of 1.

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.

  1. Create ParentComponent.js: In the “components” folder, create a new file named ParentComponent.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 function greetParent in the ParentComponent. This function will be called by the ChildComponent. It takes a childName argument and displays an alert.
    • <ChildComponent greetHandler={greetParent} />: We use the ChildComponent and pass the greetParent function as a prop named greetHandler.
  2. Create ChildComponent.js: In the “components” folder, create a new file named ChildComponent.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) => { ... }: The ChildComponent accepts props.
    • <button onClick={() => props.greetHandler('child')}>:
      • onClick={() => ...}: We attach an onClick handler to the button.
      • props.greetHandler('child'): Inside the handler, we call the greetHandler function that was passed as a prop from the parent. We pass the string ‘child’ as an argument to greetHandler.
  3. Import and Use ParentComponent in App.js:

    import React from 'react';
    import ParentComponent from './components/ParentComponent';
    
    function App() {
      return (
        <div className="App">
          <ParentComponent />
        </div>
      );
    }
    
    export default App;
  4. 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 in ChildComponent is triggered.
    • props.greetHandler('child') is called, which executes the greetParent function in ParentComponent.
    • The alert “Hello Parent, child” is displayed.

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.

  1. Create UserGreeting.js: In the “components” folder, create a new file named UserGreeting.js.

  2. 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 variable isLoggedIn to represent the login status. You can change this to false 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 syntax condition ? expressionIfTrue : expressionIfFalse.

      (condition ? valueIfTrue : valueIfFalse) to conditionally render the greeting:

      • If isLoggedIn is true, it renders ‘Vishwas’.
      • If isLoggedIn is false, it renders ‘Guest’.
  3. Import and Use UserGreeting in App.js:

    import React from 'react';
    import UserGreeting from './components/UserGreeting';
    
    function App() {
      return (
        <div className="App">
          <UserGreeting />
        </div>
      );
    }
    
    export default App;
  4. View in Browser: Save and view in the browser.

    • If isLoggedIn is true in UserGreeting.js, you’ll see “Welcome Vishwas”.
    • If isLoggedIn is false, you’ll see “Welcome Guest”.

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, in condition1 && condition2, if condition1 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 && ...: If isLoggedIn is true, the expression on the right (<div>Vishwas</div>) is evaluated and rendered.
    • If isLoggedIn is false, 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.

  1. Create NameList.js: In the “components” folder, create a new file named NameList.js.

  2. 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 the map method on the names 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 each name in the names array, the arrow function name => (...) is executed.

      • <h2 key={name}>{name}</h2>: Inside the arrow function, we return an <h2> tag. The name 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. The key 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 the key because names are unique in this list. Important: Keys must be unique within the list.

  3. Import and Use NameList in App.js:

    import React from 'react';
    import NameList from './components/NameList';
    
    function App() {
      return (
        <div className="App">
          <NameList />
        </div>
      );
    }
    
    export default App;
  4. 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:

  1. Regular CSS Stylesheets: Traditional CSS stylesheets can be imported and used in React components.
  2. Inline Styling: Styles can be applied directly to JSX elements as inline styles.
  3. CSS Modules: CSS Modules scope CSS classes locally to components, preventing naming conflicts and improving CSS organization.
  4. 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.

  1. Create Stylesheet.js: In the “components” folder, create a new file named Stylesheet.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 named MyStyles.css (which we’ll create next).
    • <h1 className='primary'>Stylesheets</h1>: We use className='primary' to apply the CSS class named primary to the <h1> element.
  2. Create MyStyles.css: In the “components” folder, create a new file named MyStyles.css.

    .primary {
      color: orange;
    }
    • We define a CSS class named primary that sets the text color to orange.
  3. Import and Use Stylesheet in App.js:

    import React from 'react';
    import Stylesheet from './components/Stylesheet';
    
    function App() {
      return (
        <div className="App">
          <Stylesheet />
        </div>
      );
    }
    
    export default App;
  4. 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.

  1. Create Inline.js: In the “components” folder, create a new file named Inline.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 object headingStyle 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 the headingStyle object to the style attribute of the <h1> element.
  2. Import and Use Inline in App.js:

    import React from 'react';
    import Inline from './components/Inline';
    
    function App() {
      return (
        <div className="App">
          <Inline />
        </div>
      );
    }
    
    export default App;
  3. 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.

  1. Create CSS Module Stylesheet: In the src folder (not “components”), create a new file named AppStyles.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) and success (green color).
  2. Create Regular CSS Stylesheet: In the src folder, create a regular CSS stylesheet named AppStyles.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).
  3. 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 the error class from the regular stylesheet, we apply it directly using className="error".
    • <h1 className={styles.success}>Success</h1>: To use the success class from the CSS Module, we access it as a property of the styles object: styles.success.
  4. 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).

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.

  1. Create Form.js: In the “components” folder, create a new file named Form.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';: Import useState hook.
    • const [username, setUsername] = useState('');: Create a state variable username to store the input value. Initialize it to an empty string.
    • const handleUsernameChange = (event) => { ... };: Define an event handler handleUsernameChange for the onChange event of the input field:
      • setUsername(event.target.value);: Update the username state with the current value of the input field (event.target.value).
    • const handleSubmit = (event) => { ... };: Define an event handler handleSubmit for the onSubmit 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 the username state.

    • <form onSubmit={handleSubmit}>: Attach the handleSubmit function to the onSubmit event of the <form> element.
    • <input type="text" value={username} onChange={handleUsernameChange} />: Create an input field of type “text”:
      • value={username}: Bind the value attribute of the input field to the username 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 the handleUsernameChange function to the onChange event. This ensures that whenever the user types into the input field, the handleUsernameChange function is called, updating the username state, and React re-renders the input field with the new value.

    • <button type="submit">Submit</button>: Create a submit button.
  2. Import and Use Form in App.js:

    import React from 'react';
    import Form from './components/Form';
    
    function App() {
      return (
        <div className="App">
          <Form />
        </div>
      );
    }
    
    export default App;
  3. 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.

  1. Create PostList.js: In the “components” folder, create a new file named PostList.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';: Import useState and useEffect 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. The useEffect hook is used to manage these side effects in function components.

    • const [posts, setPosts] = useState([]);: Create a state variable posts to store the fetched post data. Initialize it as an empty array.

    • useEffect(() => { ... }, []);: Use the useEffect 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 using response.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 call setPosts(data) to update the posts 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 to useEffect 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 the posts array.
      • <li key={post.id}>{post.title}</li>: For each post object, render a list item (<li>) displaying the post.title. Use post.id as the key prop.
  2. Import and Use PostList in App.js:

    import React from 'react';
    import PostList from './components/PostList';
    
    function App() {
      return (
        <div className="App">
          <PostList />
        </div>
      );
    }
    
    export default App;
  3. 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.

  1. Create PostForm.js: In the “components” folder, create a new file named PostForm.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, and body to manage the values of the input fields.
    • Event Handlers for Input Changes: handleUserIdChange, handleTitleChange, and handleBodyChange 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 as POST.
        • body: JSON.stringify({ ... }): Set the request body. We use JSON.stringify() to convert the JavaScript object containing title, body, and userId to a JSON string, which is the format expected by the API for POST requests.
        • headers: { 'Content-type': 'application/json; charset=UTF-8', }: Set the Content-type header to application/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.
  2. Import and Use PostForm in App.js:

    import React from 'react';
    import PostForm from './components/PostForm';
    
    function App() {
      return (
        <div className="App">
          <PostForm />
        </div>
      );
    }
    
    export default App;
  3. 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.

  1. Create data.json: In the “components” folder, create a new file named data.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 have id, firstName, and lastName properties.

  2. Modify App.js to Implement List Filtering with useTransition:

    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';: Import useTransition hook.
    • import names from './components/data.json';: Import the data.json file containing the list of names.
    • const [query, setQuery] = useState('');: State variable query to store the filter query text.
    • const [inputValue, setInputValue] = useState('');: State variable inputValue 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();: Call useTransition():
      • isPending: A boolean state variable that is true while a transition is pending (in progress) and false otherwise.
      • startTransition: A function that you use to mark state updates as transitions.
    • const filteredNames = names.filter(...): Filter the names array based on the query text.
    • const handleChange = (event) => { ... };: Input change handler:
      • setInputValue(event.target.value);: Immediately update inputValue 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 to query state as a transition (non-urgent update):
        • startTransition(() => { ... });: Call startTransition() and pass a callback function as an argument.
        • setQuery(event.target.value);: Inside the callback, update the query state. React will treat this state update as a transition.
    • {isPending ? <p>Updating list...</p> : null}: Conditionally render “Updating list…” paragraph while isPending is true (during the transition).
    • {filteredNames.map(item => ...)}: Render the filtered list of names.
  3. 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 remove startTransition): 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 because useTransition prioritizes the urgent input update, making the UI feel more responsive even during the potentially slower list filtering operation.

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!