React.js, commonly known as React, is an open-source JavaScript library for building user interfaces or UI components. It was developed by Facebook and is maintained by Facebook and a community of individual developers and companies. React is widely used for creating single-page applications where data can change over time without reloading the page. It allows developers to build reusable UI components and manage the state of an application efficiently.
The Virtual DOM is a programming concept where an ideal, or "virtual," representation of the user interface is kept in memory. It acts as a lightweight copy of the real DOM and is used for efficient updates. When the state of an object changes, React first updates the Virtual DOM, then compares it to the current state, and finally updates only the parts of the actual DOM that have changed. This minimizes the number of manipulations needed, improving performance.
JSX (JavaScript XML) is a syntax extension for JavaScript recommended by React. It looks similar to XML/HTML but ultimately gets transpiled to JavaScript. JSX allows developers to write UI components in a syntax that closely resembles HTML, making the code more readable.
Example of JSX:
const element = <h1>Hello, React!</h1>;
In the above code, <h1>Hello, React!</h1> is JSX, representing a React element. This JSX will be transformed into a React.createElement function call during the compilation process.
Output:
<h1>Hello, React!</h1>
Understanding these foundational concepts is crucial for diving into React development and building efficient and scalable applications.
Node.js: Node.js is a JavaScript runtime that allows you to run JavaScript on the server side. React development often relies on Node.js for package management and running scripts.
npm (Node Package Manager): npm is the default package manager for Node.js. It is used to install, share, and manage dependencies. React projects typically leverage npm to manage libraries and tools.
Installation:
Create React App (CRA): CRA is a command-line tool that sets up a new React project with a sensible default configuration. It allows developers to quickly start building React applications without dealing with complex configurations.
Create a New React App:
npx create-react-app my-react-app
cd my-react-app
This command creates a new React app named my-react-app and navigates into its directory.
Start the Development Server:
npm start
This command starts the development server, and you can view your React app at http://localhost:3000 in your web browser.
A typical Create React App project structure looks like this:
my-react-app/
│
├── public/
│ ├── index.html
│ └── favicon.ico
│
├── src/
│ ├── index.js
│ ├── App.js
│ ├── App.css
│ ├── index.css
│ └── logo.svg
│
├── package.json
├── README.md
└── ...
public/: Contains static assets such as HTML files, images, and the favicon.
src/: Houses the source code for the React application.
index.js: Entry point of the application where React is rendered into the DOM.App.js: The main component that gets rendered in index.js.App.css and index.css: Style files for the components.logo.svg: An example image.package.json: Configuration file that includes project metadata and dependencies.
README.md: Documentation for the project.
Understanding the project structure is essential for organizing code and assets effectively during React development.
Functional Component Definition:
A functional component is a JavaScript function that takes props (short for properties) as an argument and returns React elements. It is a simple way to define stateless or presentational components.
Example:
const Greeting = (props) => {
return <h1>Hello, {props.name}!</h1>;
};
Usage:
<Greeting name="John" />
Class Component Definition:
Class components are ES6 classes that extend React.Component. They have a render method and can have state and lifecycle methods.
Example:
class Welcome extends React.Component {
render() {
return <h1>Welcome, {this.props.user}!</h1>;
}
}
Usage:
<Welcome user="Alice" />
Props in Functional Components:
Props are passed as arguments to functional components and accessed as properties of the props object.
Example:
const Person = (props) => {
return (
<p>
Name: {props.name}, Age: {props.age}
</p>
);
};
Usage:
<Person name="Bob" age={30} />
PropTypes for Type Checking: PropTypes is a library for type-checking props during development. It helps catch bugs related to incorrect prop types.
Example:
import PropTypes from "prop-types";
const Book = (props) => {
return <h2>Title: {props.title}</h2>;
};
Book.propTypes = {
title: PropTypes.string.isRequired,
};
State in Class Components: State is used for managing component-specific data that may change over time. Class components can have state.
Example:
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
render() {
return (
<div>
<p>Count: {this.state.count}</p>
</div>
);
}
}
setState for Updating State:
setState is used to update the state of a component.
Example:
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
handleClick = () => {
this.setState({ count: this.state.count + 1 });
};
render() {
return (
<div>
<p>Count: {this.state.count}</p>
<button onClick={this.handleClick}>Increment</button>
</div>
);
}
}
JSX, or JavaScript XML, is a syntax extension for JavaScript. It allows you to write HTML-like code in your JavaScript files, making it easier to describe what the UI should look like.
const element = <h1>Hello, JSX!</h1>;
In this example, the JSX <h1>Hello, JSX!</h1> gets transpiled into a React.createElement function call during the compilation process.
You can embed JavaScript expressions within curly braces {} in JSX. This allows you to dynamically include values or execute functions.
const name = "John";
const element = <p>Hello, {name}!</p>;
Using Ternary Operator:
const isLoggedIn = true;
const greeting = isLoggedIn ? <p>Welcome back!</p> : <p>Please log in</p>;
Using Logical && Operator:
const hasMessages = true;
const messages = hasMessages && <p>You have new messages</p>;
Using Conditional Statements:
function Greeting({ isLoggedIn }) {
if (isLoggedIn) {
return <p>Welcome back!</p>;
} else {
return <p>Please log in</p>;
}
}
function handleClick() {
console.log("Button Clicked");
}
const buttonElement = <button onClick={handleClick}>Click me</button>;
Binding in Class Components:
class ButtonClick extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
console.log("Button Clicked");
}
render() {
return <button onClick={this.handleClick}>Click me</button>;
}
}
Binding with Arrow Function:
class ButtonClick extends React.Component {
handleClick = () => {
console.log("Button Clicked");
};
render() {
return <button onClick={this.handleClick}>Click me</button>;
}
}
class ParameterExample extends React.Component {
handleClick = (param) => {
console.log("Button Clicked with parameter:", param);
};
render() {
const paramValue = "Hello, React!";
return (
<button onClick={() => this.handleClick(paramValue)}>
Click me with parameter
</button>
);
}
}
const numbers = [1, 2, 3, 4, 5];
const ListComponent = () => {
return (
<ul>
{numbers.map((number) => (
<li key={number}>{number}</li>
))}
</ul>
);
};
In React, the key attribute is a special attribute used to uniquely identify elements in a list. It helps React identify which items have changed, are added, or are removed.
const ListComponent = () => {
const users = [
{ id: 1, name: "Alice" },
{ id: 2, name: "Bob" },
{ id: 3, name: "Charlie" },
];
return (
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
);
};
class ControlledForm extends React.Component {
constructor(props) {
super(props);
this.state = {
inputValue: "",
};
}
handleChange = (event) => {
this.setState({ inputValue: event.target.value });
};
render() {
return (
<form>
<label>
Name:
<input
type="text"
value={this.state.inputValue}
onChange={this.handleChange}
/>
</label>
</form>
);
}
}
class FormSubmission extends React.Component {
handleSubmit = (event) => {
event.preventDefault();
// Process form data here
};
render() {
return (
<form onSubmit={this.handleSubmit}>
<button type="submit">Submit</button>
</form>
);
}
}
React components go through three main phases: mounting, updating, and unmounting.
constructor(), render(), componentDidMount()shouldComponentUpdate(), render(), componentDidUpdate()componentWillUnmount()Example:
class LifecycleExample extends React.Component {
constructor(props) {
super(props);
console.log("Constructor");
}
componentDidMount() {
console.log("Component did mount");
}
componentDidUpdate(prevProps, prevState) {
console.log("Component did update");
}
componentWillUnmount() {
console.log("Component will unmount");
}
render() {
console.log("Render");
return <p>Component Lifecycle Example</p>;
}
}
useEffect Hook:In functional components, the useEffect hook is used to perform side effects.
import React, { useEffect } from "react";
const EffectExample = () => {
useEffect(() => {
console.log("Component did mount (equivalent)");
return () => {
console.log("Component will unmount (equivalent)");
};
}, []);
return <p>Effect Example</p>;
};
const ThemeContext = React.createContext();
const App = () => {
const theme = "light";
return (
<ThemeContext.Provider value={theme}>
<Toolbar />
</ThemeContext.Provider>
);
};
const ThemedButton = () => {
const theme = useContext(ThemeContext);
return <button style={{ background: theme }}>Themed Button</button>;
};
const ParentComponent = () => {
const [count, setCount] = useState(0);
const increment = () => {
setCount(count + 1);
};
return (
<div>
<ChildComponent count={count} increment={increment} />
</div>
);
};
const ChildComponent = ({ count, increment }) => {
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
);
};
npm install redux react-redux
const increment = () => {
return { type: "INCREMENT" };
};
const counterReducer = (state = { count: 0 }, action) => {
switch (action.type) {
case "INCREMENT":
return { count: state.count + 1 };
default:
return state;
}
};
const store = createStore(counterReducer);
const CounterComponent = () => {
const count = useSelector((state) => state.count);
const dispatch = useDispatch();
return (
<div>
<p>Count: {count}</p>
<button onClick={() => dispatch(increment())}>Increment</button>
</div>
);
};
npm install react-router-dom
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
const Home = () => <h2>Home</h2>;
const About = () => <h2>About</h2>;
const App = () => {
return (
<Router>
<div>
<nav>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
</ul>
</nav>
<Route path="/" exact component={Home} />
<Route path="/about" component={About} />
</div>
</Router>
);
};
useHistory Hook:import { useHistory } from "react-router-dom";
const NavigationComponent = () => {
const history = useHistory();
const handleClick = () => {
history.push("/about");
};
return (
<div>
<button onClick={handleClick}>Go to About</button>
</div>
);
};
import React, { useState } from "react";
const Counter = () => {
const [count, setCount] = useState(0);
const increment = () => {
setCount(count + 1);
};
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
);
};
import React, { useState, useEffect } from "react";
const DataFetchingComponent = () => {
const [data, setData] = useState([]);
useEffect(() => {
fetch("https://api.example.com/data")
.then((response) => response.json())
.then((result) => setData(result));
}, []);
return (
<div>
<ul>
{data.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
</div>
);
};
import React, { useContext } from "react";
const ThemeContext = React.createContext("light");
const ThemedComponent = () => {
const theme = useContext(ThemeContext);
return <p>Current theme: {theme}</p>;
};
import { useState, useEffect } from "react";
const useWindowWidth = () => {
const [windowWidth, setWindowWidth] = useState(window.innerWidth);
const handleResize = () => {
setWindowWidth(window.innerWidth);
};
useEffect(() => {
window.addEventListener("resize", handleResize);
return () => {
window.removeEventListener("resize", handleResize);
};
}, []);
return windowWidth;
};
const WindowWidthComponent = () => {
const width = useWindowWidth();
return <p>Window Width: {width}</p>;
};
import React from "react";
const withLogger = (WrappedComponent) => {
class WithLogger extends React.Component {
componentDidMount() {
console.log(`Component ${WrappedComponent.name} mounted`);
}
render() {
return <WrappedComponent {...this.props} />;
}
}
return WithLogger;
};
const MyComponent = () => <p>My Component</p>;
const MyComponentWithLogger = withLogger(MyComponent);
import React from "react";
class MouseTracker extends React.Component {
state = { x: 0, y: 0 };
handleMouseMove = (event) => {
this.setState({ x: event.clientX, y: event.clientY });
};
render() {
return (
<div
style={{ height: "100vh" }}
onMouseMove={this.handleMouseMove}
>
{this.props.render(this.state)}
</div>
);
}
}
const App = () => {
return (
<MouseTracker
render={({ x, y }) => (
<p>
Mouse position: {x}, {y}
</p>
)}
/>
);
};
npm install --save-dev jest enzyme enzyme-to-json enzyme-adapter-react-16
import { shallow } from "enzyme";
import MyComponent from "./MyComponent";
describe("MyComponent", () => {
it("renders correctly", () => {
const wrapper = shallow(<MyComponent />);
expect(wrapper).toMatchSnapshot();
});
it("handles click event", () => {
const mockClick = jest.fn();
const wrapper = shallow(<MyComponent onClick={mockClick} />);
wrapper.find("button").simulate("click");
expect(mockClick).toHaveBeenCalled();
});
});
npm install styled-components
import styled from "styled-components";
const Button = styled.button`
background-color: ${(props) => (props.primary ? "blue" : "white")};
color: ${(props) => (props.primary ? "white" : "black")};
padding: 10px 20px;
border: 2px solid blue;
`;
const App = () => {
return (
<div>
<Button primary>Primary Button</Button>
<Button>Secondary Button</Button>
</div>
);
};
import React from 'react';
import styles from './styles.module.css';
const Button = () => {
return (
<button className={styles.button}>
Click me
</button>
);
};
import React, { useEffect, useState } from "react";
const DataFetchingComponent = () => {
const [data, setData] = useState([]);
useEffect(() => {
const fetchData = async () => {
try {
const response = await fetch("https://api.example.com/data");
const result = await response.json();
setData(result);
} catch (error) {
console.error("Error fetching data:", error);
}
};
fetchData();
}, []);
return (
<div>
<ul>
{data.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
</div>
);
};
npm install axios
import React, { useEffect, useState } from "react";
import axios from "axios";
const DataFetchingComponent = () => {
const [data, setData] = useState([]);
useEffect(() => {
const fetchData = async () => {
try {
const response = await axios.get("https://api.example.com/data");
setData(response.data);
} catch (error) {
console.error("Error fetching data:", error);
}
};
fetchData();
}, []);
return (
<div>
<ul>
{data.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
</div>
);
};
import React, { useMemo } from "react";
const ExpensiveComponent = ({ data }) => {
const processedData = useMemo(() => {
return data.map((item) => item * 2);
}, [data]);
return (
<div>
{processedData.map((item) => (
<p key={item}>{item}</p>
))}
</div>
);
};
import React, { memo } from "react";
const MemoizedComponent = memo(({ data }) => {
console.log("Rendered!");
return <p>Memoized Component</p>;
});
React DevTools Profiler: Inspect and identify performance bottlenecks.
React.StrictMode:
const App = () => {
return <React.StrictMode>{/* Your app components */}</React.StrictMode>;
};
if ("serviceWorker" in navigator) {
navigator.serviceWorker
.register("/service-worker.js")
.then((registration) => {
console.log(
"Service Worker registered with scope:",
registration.scope
);
})
.catch((error) => {
console.error("Error registering Service Worker:", error);
});
}
self.addEventListener("install", (event) => {
event.waitUntil(
caches.open("my-cache").then((cache) => {
return cache.addAll(["/", "/index.html", "/app.js"]);
})
);
});
self.addEventListener("fetch", (event) => {
event.respondWith(
caches.match(event.request).then((response) => {
return response || fetch(event.request);
})
);
});
import React, { useReducer } from "react";
const initialState = { count: 0 };
const reducer = (state, action) => {
switch (action.type) {
case "increment":
return { count: state.count + 1 };
case "decrement":
return { count: state.count - 1 };
default:
return state;
}
};
const Counter = () => {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: "increment" })}>
Increment
</button>
<button onClick={() => dispatch({ type: "decrement" })}>
Decrement
</button>
</div>
);
};
import React, { useState } from "react";
const Accordion = ({ children }) => {
const [openIndex, setOpenIndex] = useState(null);
const handleToggle = (index) => {
setOpenIndex((prevIndex) => (prevIndex === index ? null : index));
};
return React.Children.map(children, (child, index) =>
React.cloneElement(child, {
isOpen: index === openIndex,
onToggle: () => handleToggle(index),
})
);
};
const AccordionItem = ({ isOpen, onToggle, title, children }) => {
return (
<div>
<div onClick={onToggle} style={{ cursor: "pointer" }}>
<h3>{title}</h3>
</div>
{isOpen && <div>{children}</div>}
</div>
);
};
import React, { lazy, Suspense } from "react";
const LazyComponent = lazy(() => import("./LazyComponent"));
const App = () => {
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
</div>
);
};
import React, { Component } from "react";
class ErrorBoundary extends Component {
state = { hasError: false, error: null };
static getDerivedStateFromError(error) {
return { hasError: true, error };
}
componentDidCatch(error, errorInfo) {
logErrorToService(error, errorInfo);
}
render() {
if (this.state.hasError) {
return <p>Something went wrong.</p>;
}
return this.props.children;
}
}
import React from "react";
const AccessibleButton = ({ onClick, label }) => {
return (
<button onClick={onClick} aria-label={label}>
{label}
</button>
);
};
// App.js
import React, { useState } from "react";
import TaskList from "./TaskList";
import AddTaskForm from "./AddTaskForm";
const App = () => {
const [tasks, setTasks] = useState([]);
const addTask = (task) => {
setTasks([...tasks, task]);
};
return (
<div>
<h1>Task Manager</h1>
<AddTaskForm onAddTask={addTask} />
<TaskList tasks={tasks} />
</div>
);
};
export default App;
import React, { useState, useEffect } from "react";
import TaskList from "./TaskList";
import AddTaskForm from "./AddTaskForm";
const App = () => {
const [tasks, setTasks] = useState([]);
useEffect(() => {
fetch("https://api.example.com/tasks")
.then((response) => response.json())
.then((data) => setTasks(data))
.catch((error) =>
console.error("Error fetching tasks:", error)
);
}, []);
const addTask = (task) => {
fetch("https://api.example.com/tasks", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(task),
})
.then((response) => response.json())
.then((newTask) => setTasks([...tasks, newTask]))
.catch((error) => console.error("Error adding task:", error));
};
return (
<div>
<h1>Task Manager</h1>
<AddTaskForm onAddTask={addTask} />
<TaskList tasks={tasks} />
</div>
);
};
export default App;
Problem Statement: Implement a simple counter component in React that increments or decrements a value based on user actions.
import React, { useState } from "react";
const Counter = () => {
const [count, setCount] = useState(0);
const increment = () => setCount(count + 1);
const decrement = () => setCount(count - 1);
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
</div>
);
};
export default Counter;
| Real DOM | Virtual DOM |
|---|---|
| It updates slow | It updates faster |
| Can directly update HTML | Can't directly update HTML |
| Creates a new DOM if element updates | Updates the JSX if element updates |
| DOM manipulation is very expensive | DOM manipulation is very easy |
| Too much of memory wastage | No memory wastage |
| State | Props |
|---|---|
| State is mutable. | Props are immutable. |
| State is local to the component. | Props can be accessed by child components. |
| State can be changed by the component itself. | Props can't be changed by the component itself. |
| State affects only the component it's in. | Props can affect several components, but only in one direction. |
| Controlled Components | Uncontrolled Components |
|---|---|
| Form data is handled by a React component. | Form data is handled by the DOM itself. |
| State is initialized and updated by the component. | State is handled by the DOM. |
setState() is used to update state. |
A ref is used to update state. |
| Controlled components provide better performance. | Uncontrolled components use less code. |