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.stateandthis.setState(). - utilize lifecycle methods (e.g.,
componentDidMount,componentWillUnmount).
Code Example
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
thiskeyword. - Access props directly as function arguments.
- Use Hooks (
useState,useEffect) to manage state and lifecycle.
Code Example
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
- Render: When data changes in a component, React renders the component to a new Virtual DOM tree.
- 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).
- 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
- Unidirectional Data Flow: Data flows one way: down from parent to child.
- Read-Only (Immutable): A component must never modify its own props. They are "pure" with respect to their inputs.
- Destructuring: Commonly used to extract specific properties from the props object.
Passing and Accessing Props
Parent Component:
<UserProfile username="JohnDoe" age={25} isAdmin={true} />
Child Component (Functional):
// 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.
// 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-colorbecomesbackgroundColor). - Values are strings (unless they are unitless numbers like
zIndexoropacity).
Example
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
- Create
App.css. - Import it:
import './App.css'; - Use
className(notclass) in JSX.
App.css
.primary-btn {
background-color: blue;
color: white;
}
App.js
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
- Name the file with the extension
.module.css(e.g.,Button.module.css). - Import the file as a variable (usually named
stylesorclasses). - Access classes as properties of that object.
Button.module.css
.error {
background-color: red;
}
Button.js
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
.containerin 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)
- Install via npm:
BASHnpm install -D tailwindcss postcss autoprefixer npx tailwindcss init -p - Configure
tailwind.config.js:
Add the paths to all of your template files so Tailwind can tree-shake unused styles.
JAVASCRIPTmodule.exports = { content: [ "./src/**/*.{js,jsx,ts,tsx}", ], theme: { extend: {} }, plugins: [], } - 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.
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).