Unit 2 - Notes

INT252

Unit 2: Components and styles in React

1. Creating Components

Components are the independent, reusable building blocks of a React application. Conceptually, components are like JavaScript functions. They accept arbitrary inputs (called "props") and return React elements describing what should appear on the screen.

Key Principles

  • Reusability: Write code once and use it in multiple places.
  • Separation of Concerns: Split the UI into independent, isolated pieces.
  • Composition: Build complex UIs by nesting simpler components.
  • Naming Convention: React component names must always start with a capital letter (PascalCase). If a component starts with a lowercase letter, React treats it as a DOM tag (like <div> or <span>).

2. Class Components

Before React 16.8 (Hooks), class components were the only way to track state and lifecycle methods. While modern React prefers functional components, understanding class components is essential for maintaining legacy codebases.

Characteristics

  • Must extend React.Component.
  • Must implement a render() method that returns JSX.
  • Access props via this.props.
  • Handle state using this.state and this.setState().
  • utilize lifecycle methods (e.g., componentDidMount, componentWillUnmount).

Code Example

JSX
import React, { Component } from 'react';

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

  render() {
    return (
      <div>
        <h1>Hello, {this.props.name}</h1>
        <p>Count: {this.state.count}</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Increment
        </button>
      </div>
    );
  }
}

export default Welcome;


3. Functional Components

Functional components are JavaScript functions. With the introduction of Hooks (React 16.8), they can now handle state and side effects, making them the standard for modern React development.

Characteristics

  • Simpler syntax (less boilerplate code).
  • Do not use the this keyword.
  • Access props directly as function arguments.
  • Use Hooks (useState, useEffect) to manage state and lifecycle.

Code Example

JSX
import React, { useState } from 'react';

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

  return (
    <div>
      <h1>Hello, {props.name}</h1>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>
        Increment
      </button>
    </div>
  );
};

export default Welcome;

Comparison: Class vs. Functional

Feature Class Components Functional Components
Syntax ES6 Class JavaScript Function
State this.state object useState Hook
Props this.props Function arguments (props)
Lifecycle componentDidMount, etc. useEffect Hook
Complexity Higher (requires this binding) Lower (cleaner code)

4. React Virtual DOM

The Virtual DOM (VDOM) is a programming concept where a virtual representation of the UI is kept in memory and synced with the "real" DOM by a library such as ReactDOM. This process is called Reconciliation.

How it Works

  1. Render: When data changes in a component, React renders the component to a new Virtual DOM tree.
  2. Diffing: React compares the new Virtual DOM tree with the previous Virtual DOM tree to figure out exactly what changed. This uses a "diffing algorithm" (heuristic O(n) complexity).
  3. Update: React updates only the changed nodes in the real Browser DOM.

Why is it faster?

Manipulating the real Browser DOM is slow because it triggers layout recalculations (reflow) and repainting. The Virtual DOM is a lightweight JavaScript object. Changing the object is fast. By batching updates and only touching the real DOM where necessary, React optimizes performance.


5. Props (Properties)

Props are inputs passed from a parent component to a child component. They allow components to be dynamic and reusable.

Core Concepts

  1. Unidirectional Data Flow: Data flows one way: down from parent to child.
  2. Read-Only (Immutable): A component must never modify its own props. They are "pure" with respect to their inputs.
  3. Destructuring: Commonly used to extract specific properties from the props object.

Passing and Accessing Props

Parent Component:

JSX
<UserProfile username="JohnDoe" age={25} isAdmin={true} />

Child Component (Functional):

JSX
// Option 1: Standard
const UserProfile = (props) => {
  return <h1>{props.username} is {props.age}</h1>;
};

// Option 2: Destructuring (Best Practice)
const UserProfile = ({ username, age, isAdmin }) => {
  return (
    <div>
      <h1>{username}</h1>
      {isAdmin && <span>Administrator</span>}
    </div>
  );
};

The children Prop

props.children is a special prop that allows you to pass elements inside the opening and closing tags of a component, rather than as an attribute.

JSX
// Usage
<Card>
  <h2>Title</h2>
  <p>This content is passed as children.</p>
</Card>

// Component Definition
const Card = ({ children }) => {
  return <div className="card-container">{children}</div>;
};


6. CSS in React (Overview)

React does not enforce a specific way to style components. Styles can be defined using standard CSS, preprocessors (Sass), CSS-in-JS, or utility frameworks. The goal is to ensure styles are maintainable and avoid global namespace collisions.


7. Inline Styling

In React, inline styles are not provided as a string. Instead, they are specified as an object.

Syntax Rules

  • Style properties are written in camelCase (e.g., background-color becomes backgroundColor).
  • Values are strings (unless they are unitless numbers like zIndex or opacity).

Example

JSX
const divStyle = {
  color: 'blue',
  backgroundColor: 'lightgray',
  padding: '10px',
  fontSize: '20px'
};

const StyledComponent = () => {
  // Passing the object directly
  return <div style={divStyle}>I am styled inline!</div>;
};

  • Pros: Scoped to the element; easy to make dynamic based on state.
  • Cons: Cannot use pseudo-classes (:hover), media queries, or keyframes easily; clutters the JSX.

8. CSS Stylesheets

This involves writing standard CSS in a separate .css file and importing it into the React component.

Usage

  1. Create App.css.
  2. Import it: import './App.css';
  3. Use className (not class) in JSX.

App.css

CSS
.primary-btn {
  background-color: blue;
  color: white;
}

App.js

JSX
import './App.css';

const App = () => {
  return <button className="primary-btn">Click Me</button>;
};

  • Drawback: Global Scope. If two CSS files define .primary-btn, the cascading nature of CSS will apply the one defined last to the entire application, potentially causing layout breakage.

9. CSS Modules

CSS Modules solve the global scoping problem of standard stylesheets. A CSS Module is a CSS file where all class names and animation names are scoped locally by default.

How it Works

  1. Name the file with the extension .module.css (e.g., Button.module.css).
  2. Import the file as a variable (usually named styles or classes).
  3. Access classes as properties of that object.

Button.module.css

CSS
.error {
  background-color: red;
}

Button.js

JSX
import styles from './Button.module.css';

const Button = () => {
  // React compiles this to a unique class name like "Button_error__ax7yz"
  return <button className={styles.error}>Error Button</button>;
};

  • Benefit: You can use the class name .container in ten different components, and CSS Modules will generate unique class names for the browser, preventing conflicts.

10. Adding TailwindCSS

Tailwind CSS is a "utility-first" CSS framework. Instead of writing custom CSS classes, you apply pre-defined utility classes directly in your JSX.

Installation Steps (General Flow)

  1. Install via npm:
    BASH
        npm install -D tailwindcss postcss autoprefixer
        npx tailwindcss init -p
        
  2. Configure tailwind.config.js:
    Add the paths to all of your template files so Tailwind can tree-shake unused styles.
    JAVASCRIPT
        module.exports = {
          content: [
            "./src/**/*.{js,jsx,ts,tsx}",
          ],
          theme: { extend: {} },
          plugins: [],
        }
        
  3. Add directives to your main CSS file (e.g., index.css):
    CSS
        @tailwind base;
        @tailwind components;
        @tailwind utilities;
        

Usage in React

You use standard React className props with Tailwind utility classes.

JSX
const Card = () => {
  return (
    <div className="max-w-sm rounded overflow-hidden shadow-lg bg-white">
      <div className="px-6 py-4">
        <div className="font-bold text-xl mb-2 text-gray-800">
          Tailwind Card
        </div>
        <p className="text-gray-700 text-base">
          Styling with utilities is fast and consistent.
        </p>
      </div>
    </div>
  );
};

Benefits

  • Speed: No switching between JS and CSS files.
  • File Size: Purges unused CSS in production, resulting in tiny CSS bundles.
  • Consistency: Uses a predefined design system (colors, spacing, typography).