React - Work In Progress
React Component Essentials
- Definition: React’s fundamental building block.
- Characteristics:
- Combines UI logic and appearance.
- Ranges from small (e.g., a button) to large (e.g., a page).
- Essentially JS functions returning UI markup.
// JSX
function MyButton() {
return (
<button>
Click Me!
</button>
);
}
After declaring this button component, we can nest it inside of another component.
// JSX
export default function MyApp() {
return (
<div>
<h1>Welcome to my app!</h1>
<MyButton />
</div>
);
}
React Component | HTML Tag | |
---|---|---|
Appearance | <MyButton /> | <button> |
first letter | Capitalized | Lowercase |
JSX in React
- Nature: Syntax extension for JavaScript.
- Features:
- Mixes markup with JS.
- Compiled to JS, resembling HTML.
- Requires closed tags and a single root element.
- Tooling: Supported by standard React tools.
- HTML to JSX converter
React Component vs. JSX Tags
React Component | JSX Tags |
---|---|
Combines JSX, logic, appearance | Represents DOM elements in JSX syntax |
Styling React Components
Use className
for CSS classes, not class
.
// JSX
<img className="avatar" />
/* CSS */
.avatar {
border-radius: 50%;
}
Adding CSS: Use <link>
in HTML or consult documentation for build tools/frameworks.
Displaying Data with JSX
- Integration: JSX seamlessly combines JavaScript and markup.
- Mechanism: Use curly braces
{}
to embed JavaScript within JSX. - Usage: Embed variables, expressions, and even entire components.
Embedding Variables
Embed JavaScript variables directly into JSX to display dynamic data.
// JSX
function UserGreeting() {
const user = { name: 'Alice' };
return (
<h1>Welcome, {user.name}!</h1>
);
}
Embedding Expressions
Expressions can be used for more dynamic content.
// JSX
function UserGreeting() {
const user = { name: 'Bob', age: 30 };
return (
<h1>
{user.name} is {user.age} years old.
</h1>
);
}
Dynamic Attributes
Use curly braces to dynamically set attributes like className
and src
.
// JSX
function UserProfile() {
const user = {
imageUrl: 'path/to/image.jpg',
altText: 'User Profile Picture'
};
return (
<img src={user.imageUrl} alt={user.altText} />
);
}
Conditional Rendering in JSX
- Approach: Utilize JavaScript’s conditional logic within JSX.
- Techniques:
if
statements, ternary operators, logical operators.
Using if
Statement
// JSX
function WelcomeMessage({ isLoggedIn }) {
let message;
if (isLoggedIn) {
message = <span>Welcome back!</span>;
} else {
message = <span>Please sign in.</span>;
}
return message;
}
Ternary Operator
A concise way to render components conditionally.
// JSX
function WelcomeMessage({ isLoggedIn }) {
return (
<div>
{isLoggedIn ? <span>Welcome back!</span> : <span>Please sign in.</span>}
</div>
);
}
Logical Operator (&&
)
Useful for rendering something only if a condition is true.
// JSX
function Alert({ show, message }) {
return (
<div>
{show && <div className="alert">{message}</div>}
</div>
);
}
Rendering Lists in React
- Key Concept: Use JavaScript’s array methods like
.map()
to render lists. - Key Prop: Use
key
prop for list items for efficient rendering.
Example: Rendering an Array of Items
// JSX
function FruitList() {
const fruits = ['Apple', 'Banana', 'Cherry'];
return (
<ul>
{fruits.map((fruit, index) => <li key={index}>{fruit}</li>)}
</ul>
);
}
- Note: Always provide a unique
key
prop to each list item to help React identify which items have changed, added, or removed.
Handling Events in React
- Overview: React allows you to handle events similar to handling events in regular JavaScript but with a JSX syntax twist.
Basic Event Handling
Inline functions or methods are commonly used as event handlers in React.
// JSX
function ActionButton() {
const handleClick = () => {
alert('Button clicked!');
};
return (
<button onClick={handleClick}>Click Me</button>
);
}
Notice: The onClick
attribute in JSX takes a function (here, handleClick
) as its value, which gets executed when the event occurs.
Passing Arguments to Event Handlers
You can pass additional data to event handlers using arrow functions.
// JSX
function ItemList({ items }) {
const handleItemClick = (item) => {
alert(`You selected ${item}`);
};
return (
<ul>
{items.map(item =>
<li key={item} onClick={() => handleItemClick(item)}>{item}</li>
)}
</ul>
);
}
Notice: Each list item (<li>
) has an onClick
event that calls handleItemClick
with the current item as an argument, demonstrating how to pass additional data to the handler.
Updating the UI with State
- Concept: State in React allows you to manage data that changes over time and automatically re-render the component when the data changes.
Using useState
to Track State
The useState
hook is used to add state to a functional component.
// JSX
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
const increment = () => {
setCount(count + 1);
};
return (
<div>
<p>You clicked {count} times</p>
<button onClick={increment}>Increment</button>
</div>
);
}
Notice: useState
initializes the count
state variable. The setCount
function is used to update count
, and the component re-renders each time the state changes.
State and Event Handling Together
Combining state with event handlers enables interactive UIs.
// JSX
function TextInput() {
const [text, setText] = useState('');
const handleChange = (event) => {
setText(event.target.value);
};
return (
<input type="text" value={text} onChange={handleChange} />
);
}
Notice: The text
state is updated with every keystroke in the input field, showcasing a real-time update of the state based on user input.
Propagating State Changes
- Lifting State Up: Moving state to a common ancestor component allows different components to share and update the same state.
Example: Sharing State Between Components
// JSX
import { useState } from 'react';
function ParentComponent() {
const [sharedData, setSharedData] = useState('Initial Value');
return (
<>
<ChildComponentA data={sharedData} />
<ChildComponentB updateData={setSharedData} />
</>
);
}
function ChildComponentA({ data }) {
return <p>Data from parent: {data}</p>;
}
function ChildComponentB({ updateData }) {
return (
<button onClick={() => updateData('Updated Value')}>
Update Data
</button>
);
}
Notice: ParentComponent
holds the state (sharedData
) and passes it to ChildComponentA
and ChildComponentB
. ChildComponentB
can update sharedData
via updateData
, demonstrating the concept of lifting state up and sharing it across components.
Handling Side Effects with useEffect
- Overview:
useEffect
is used for side effects in functional components, like data fetching, subscriptions, or manually changing the DOM.
Basic Usage of useEffect
useEffect
runs after every render by default.
// JSX
import { useEffect } from 'react';
function UserComponent({ userId }) {
useEffect(() => {
// Fetch user data
fetchData(userId);
});
// Component render logic
}
Notice: The useEffect
hook is used to perform side effects, such as fetching data based on userId
. It runs after every render of UserComponent
.
Conditional Execution in useEffect
Run useEffect
only when certain values change by passing them in an array.
// JSX
useEffect(() => {
// Fetch user data
fetchData(userId);
}, [userId]); // Only re-run if userId changes
Notice: useEffect
will only re-run when userId
changes, optimizing performance by avoiding unnecessary data fetching on every render.
Optimizing Performance in React
- Concept: React provides several methods to optimize the performance of applications, such as
React.memo
,useCallback
, anduseMemo
.
Using React.memo
for Component Memoization
React.memo
is a higher-order component that memoizes your component.
// JSX
import React from 'react';
const MyComponent = React.memo(function MyComponent(props) {
// Component logic
});
Notice: React.memo
prevents unnecessary re-renders of MyComponent
if its props haven’t changed, enhancing performance, especially in large and complex component trees.
useCallback
for Memoizing Functions
useCallback
returns a memoized version of the callback that only changes if one of the dependencies has changed.
// JSX
import { useCallback } from 'react';
function MyComponent() {
const memoizedCallback = useCallback(
() => {
// Function logic
},
[], // Dependencies
);
// Component logic
}
Notice: useCallback
is useful when passing callbacks to optimized child components that rely on reference equality to prevent unnecessary renders.
Using Context for State Management
- Overview: The Context API allows you to manage and share state across multiple components without prop drilling.
Creating a Context
Define a Context for your state.
// JSX
import React, { createContext, useState } from 'react';
const MyContext = createContext();
function MyApp() {
const [sharedState, setSharedState] = useState('initial value');
return (
<MyContext.Provider value={{ sharedState, setSharedState }}>
{/* Rest of your app */}
</MyContext.Provider>
);
}
Notice: MyContext.Provider
wraps your app components, allowing any child component to access and manipulate sharedState
.
Consuming Context in a Component
Use the useContext
hook to access context in a component.
// JSX
import React, { useContext } from 'react';
import MyContext from './MyContext';
function MyComponent() {
const { sharedState, setSharedState } = useContext(MyContext);
// Component logic using sharedState
}
Notice: useContext(MyContext)
provides access to sharedState
and setSharedState
, enabling the component to interact with the shared state without prop drilling.