Unit 4 Notes
Unit 4 Notes
Unit-4
Definition:
ReactJS is a JavaScript library for building user interfaces (UIs), especially for single-page
applications (SPAs). Maintained by Meta (formerly Facebook) and a large community of
developers.It focuses on building UI components that manage their own state and then compose
them to create complex UIs.
Need of ReactJs?
Reusable Components
Performance
Declarative
Community & Ecosystem
Reusable Components:
In React, a component is a piece of UI (User Interface) that is self-contained and independent.
Components can be small like a button or large like an entire form. They can accept input
(props) and return a React element that describes how a section of the UI should appear.
Once a component is created, it can be used in multiple places with different data by
passing props.
Example:
function Button(props) {
return <button>{props.label}</button>;
}
// Reuse the same Button component:
<Button label="Submit" />
<Button label="Cancel" />
<Button label="Login" />
React encourages the DRY principle (Don’t Repeat Yourself) by breaking the UI into
reusable pieces.
Advantages:
The Virtual DOM is faster and more efficient, reducing unnecessary re-rendering.
Benefits:
Faster updates → better performance
Smooth user experiences, even in data-heavy or interactive applications
Declarative Programming
In React, we describe what the UI should look like for a given state, and React
handles updating the DOM accordingly.
Declarative vs Imperative
Imperative (Traditional JS) Declarative (React)
Can manually manipulate the DOM Can describe the UI, React updates the DOM
More complex and error-prone Simpler, cleaner, easier to debug
Example:
function Greeting(props) {
return <h1>{props.isLoggedIn ? 'Welcome Back!' : 'Please Log In'}</h1>;
}
Advantages:
Simplifies logic
Easier to understand and maintain
UI always stays in sync with your data/state
JSX is a syntax extension that allows you to write HTML-like code inside JavaScript.
It makes your code easier to understand by visually combining markup and logic.
3. Functional Components
A function that returns JSX.
Preferred way to write components in modern React (especially with hooks).
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
4. Props (Properties)
Props are used to pass data from one component (usually the parent) to another
(child).
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
<Welcome name="Bob" />
5. Rendering Components
To render a component into the DOM, use ReactDOM.render():
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
6. State in React (using Hooks)
State is used to store data that changes over time within a component.
React provides a special Hook called useState for this:
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
);
}
useState(0) creates a count variable with initial value 0.
setCount is a function that updates count.
7. Event Handling
React uses camelCase for event names and passes functions as event handlers.
<button onClick={handleClick}>Click Me</button>
Example:
function handleClick() {
alert("Button clicked!");
Props are used to pass data from parent components to their children.
They are read-only within the child component, ensuring unidirectional data flow.
Props can be of any data type, including functions, allowing for callback functions to
be passed down.
This is the most common and straightforward way to share data between components.
Example:
function ParentComponent() {
const message = "Hello from parent!";
return <ChildComponent text={message} />;
}
function ChildComponent(props) {
return <p>{props.text}</p>;
}
Callback Functions (Passing Data Up):
To communicate from child to parent, a callback function can be passed as a prop.
The child component can then invoke this function, passing data back to the parent.
This allows the parent to update its state or perform actions based on the child's
interaction.
Example:
function ParentComponent() {
const handleChildClick = (data) => {
console.log("Data from child:", data);
};
return <ChildComponent onButtonClick={handleChildClick} />;
}
function ChildComponent(props) {
const handleClick = () => {
props.onButtonClick("Data from child");
};
return <button onClick={handleClick}>Click me</button>;
}
State Lifting:
When multiple components need to share and modify the same data, the state can be "lifted"
to their nearest common ancestor.
This parent component then manages the shared state and passes it down to the relevant
children as props.
This ensures a single source of truth for the data and simplifies state management.
Context API:
The Context API provides a way to share values like state between components without
having to explicitly pass a prop through every level of the tree.
It is designed to share data that can be considered "global" for a tree of React components,
such as the current authenticated user, theme, or preferred language.
Third-party Libraries (e.g., Redux, Zustand):
For complex applications with more intricate state management needs, libraries like
Redux or Zustand can be employed.
These libraries provide a centralized store for managing application state and offer
more advanced patterns for communication between components.
Choosing the appropriate communication method depends on the specific
requirements and complexity of the application. For simpler scenarios, props and
callback functions often suffice, while more complex applications may benefit from
state lifting, Context API or dedicated state management libraries.
Types of components:
React components are reusable and independent building blocks that define pieces of the user
interface. They can be classified into several types based on their characteristics and
functionality:
Functional Components: These are simple JavaScript functions that accept props
as arguments and return React elements. They are primarily used for
presentational purposes and do not manage state or lifecycle methods unless used
with hooks.
Ex:
function MyComponent(props) {
return <h1>Hello, {props.name}!</h1>;
}
}
}
function App() {
return <Greeting name="Jiya" />;
}
export default App;
npx create-react-app
Step 2: We will create components in our file namely App.js. After using this
ParentComponent.js and ChildComponent.
Step 3: Write the following code in respective files.
App.js: This file imports our ParentComponent and renders it on the page.
ParentComponent.js: This file sends methods as props to child component.
ChildComponent: This file calls the method passed prom parent as props.
import './App.css';
import React from 'react';
// imports component
import ParentComponent from './components/ParentComponent';
function App() {
return (
<div className="App">
<h1>-----------METHODS AS PROPS-------------</h1>
<ParentComponent />
</div>);
}
export default App;
Passing parameters to parents in methods as props
Till now we learned how to pass methods as props but now we will use the same technique
to pass parameters in these methods as props.
Note: We will be using the same files made in the previous example. Just some code
modification will be there.
Example: Write the following code in the respective files.
App.js: This file imports our ParentComponent and renders it on the page.
ParentComponent.js: This file sends methods as props to child component.
ChildComponent: This file calls the method passed prom parent as props and passes a
parameter to the parent.
// App.js
import './App.css';
import React from 'react';
// imports component
import ParentComponent from './components/ParentComponent';
function App() {
return (
<div className="App">
<h1>-----------METHODS AS PROPS-------------</h1>
<ParentComponent />
</div>);
}
export default App;
PropTypes
In ReactJS PropTypes are the property that is mainly shared between the parent components
to the child components. It is used to solve the type validation problem.
What is ReactJS PropTypes?
PropTypes is a tool in React that helps us check if the data (props) being passed to a
component is of the correct type. The react components receive various types of props and
PropTypes help make sure that the right kind of data (like a string, number, or object) is
passed to your components.
Type Safety: When the wrong data type is passed in the component, prototypes help find
the issues.
Better Debugging: During development, they give warning messages in the console,
which makes it easier to find the bugs.
Improved Documentation: It acts as self-documentation for your components, showing
the expected types of props.
Prevents Runtime Errors: We can avoid errors caused by unexpected data types during
the execution of the application, by enforcing prop types.
Context Hooks
The useContext hook in React is a powerful and convenient way to consume values from
the React Context API in functional components. It allows functional components to access
context values directly, without the need to manually pass props down through the component
tree
const contextValue = useContext(MyContext);
const contextValue = useContext(MyContext);
The useContext hook takes a context object (MyContext) as an argument and returns
the current value of that context.
The contextValue will hold the value provided by the nearest <MyContext.Provider> in
the component tree.
Now let’s understand how context hook works using this example
function ThemeDisplay() {
const theme = useContext(ThemeContext);
return <h2>Theme from Context: {theme}</h2>
;
}
Effect Hooks
Effect hooks, specifically useEffect, useLayoutEffect, and useInsertionEffect, enable
functional components to handle side effects in a more efficient and modular way.
useEffect: The useEffect hook in React is used to handle side effects in functional
components. It allows you to perform actions such as data fetching, DOM manipulation,
and setting up subscriptions, which are typically handled in lifecycle methods
like componentDidMount or componentDidUpdate in class components.
Syntax
useEffect(() => {
// Side effect logic here
}, [dependencies]);
useEffect(() => { … }, [dependencies]); runs side effects after rendering.
The effect runs based on changes in the specified dependencies.
Syntax
const memoizedCallback = useCallback(() => { doSomething(a, b); }, [a, b]);
useMemo caches the computed value (num * 2), recalculating it only when num
changes.
This prevents unnecessary calculations on every render.
Now let’s understand how performance hook works using this example
<input
type="text"
value={text}
onChange={(e) => setText(e.target.value)}
placeholder="Type something"
/>
</div>
);
}
export default App;
In this syntax
state: The current state value.
setState: A function that is used to update the state.
initialState: The initial value that the state will hold when the component is first
rendered.
Creating State Object
Creating a state in React is essential to building dynamic and interactive components. We can
create a state object within the constructor of the class component.
import React from 'react';
};
}
render() {
return (
<div>
<h1>My Car</h1>
{/* Other component content */}
</div>);
}
}
export default MyComponent;
ReactJS setState()
In React, setState() is an essential method used to update the state of a component, triggering
a re-render of the component and updating the UI. This method allows React to efficiently
manage and render changes in the component’s state.
What is setState()?
setState() is a method used to update the state in a React component. When we call this method,
React schedules an update to the state and triggers a re-render of the component. The key
advantage of using setState() is that it is declarative. Instead of manually manipulating
the DOM, you simply inform React of the changes to state, and React handles the rendering
for you.
Syntax
this.setState(updater, callback);
updater: An object or a function that represents the changes to be applied to the
component’s state.
callback (optional): A function that is executed once the state has been updated and the
component has re-rendered.
Key Points About setState()
1. State is Immutable: Direct modification of state is not allowed in React. Instead, you
use setState() to change it.
2. Triggers Re-render: When setState() is called, React schedules a re-render of the
component to reflect the updated state.
3. Merging State: React merges the object passed to setState() with the current state. If the
new state has a key already present in the old state, it updates the value. If not, it adds a
new key-value pair.
4. Asynchronous: setState() is asynchronous. The state update doesn’t happen immediately
but is scheduled, and React will update the component at an optimal time.
How Does setState() Work?
Triggers Re-render: When setState() is called, React schedules an update to the
component’s state and triggers a re-render. The updated state is reflected in the
component’s output.
Merging States: setState() merges the new state with the current state. This is especially
useful when you only want to update part of the state, leaving other properties intact.
Asynchronous Updates: setState() updates the state asynchronously, meaning the changes
don’t happen immediately. React batches the updates for performance reasons, and the re-
render will happen once all the updates have been processed.
Example Usage of setState()
in this code
setState() is called inside the increment method to update the count state when the
button is clicked.
This triggers a re-render, and the updated count is displayed on the UI.
Using a Function for setState()
You can also pass a function to setState(), which is useful when the new state depends on
the previous state. This function will receive the previous state and props as arguments and
should return the updated state.
import React, { Component } from 'react';
return (
<div>
<h1>Counter: {this.state.count}</h1>
<button onClick={this.increment}>Increment</button>
</div>);
}
}
export default Counter;
Updating Attributes
When updating state with setState(), you can modify the attributes of the current state, adding
or changing values as needed.
// Filename - App.js
import React, { Component } from "react";
class App extends Component {
constructor(props) {
super(props);
// Set initial state
this.state = {
greeting:
"Click the button to receive greetings",
};
// Binding this keyword
this.updateState = this.updateState.bind(this);
}
updateState() {
// Changing state
this.setState({
greeting: "GeeksForGeeks welcomes you !!",
});
}
render() {
return (
<div>
<h2>Greetings Portal</h2>
<p>{this.state.greeting}</p>
One of the most important things to understand about setState() is that it is asynchronous.
When you call setState(), React doesn’t immediately update the state. Instead, it batches
multiple state updates and processes them later in an optimal way.
However, React provides a callback function that you can pass to setState() to run code after
the state has been updated and the component has re-rendered.
this.setState(
{ count: this.state.count + 1 },
() => {
console.log('State updated:', this.state.count);
}
);
Props, short for properties, serve as a mechanism for passing data from parent components
to child components in React. They are immutable, meaning a child component cannot
directly modify the props it receives. This unidirectional data flow helps maintain
predictability and simplifies debugging.
To pass data using props, you specify attributes on the child component when it is
rendered within the parent component. The attribute names become the prop names, and
their values are the data being passed.
function ParentComponent() {
const message = "Hello from parent!";
return <ChildComponent text={message} />;
}
function ChildComponent(props) {
return <p>{props.text}</p>;
}
In this example, ParentComponent passes the string "Hello from
parent!" to ChildComponent through the text prop. ChildComponent then accesses this data
using props.text and renders it within a paragraph element.
Props can also be used to pass functions as data, enabling child components to communicate
events or actions back to their parents.
function ParentComponent() {
const handleClick = () => {
console.log("Button clicked in child!");
};
Installation Steps:
To set up a React JS development environment using npm, you'll need to install Node.js
and npm, then use the create-react-app tool. This tool simplifies the process of creating new
React projects with a pre-configured structure.
step-by-step installation:
1. Install Node.js and npm: Node.js provides a runtime environment for JavaScript code,
and npm is its package manager. You can download and install Node.js from the official
Node.js website. npm is usually included with Node.js installations.
2. Verify Installation: Open your terminal or command prompt and run node -v and npm
-v to confirm that both are installed and the versions are displayed.
3. Install Create React App: Use the following command to install create-react-
app globally:
npm install -g create-react-app.
5. Create a New React Project: Navigate to the desired directory in your terminal and
use the command: create-react-app my-app (replace my-app with your desired project
name).
create-react-app my-app
cd my-app
5. Navigate to the Project Directory: Use cd my-app to enter the newly created project
folder.
6. Start the Development Server: Run the command npm start to start the development
server and open your React app in your web browser.
npm start
To optimize code in React, developers can implement several strategies that enhance
performance and efficiency. Some of these include:
Code Splitting:
Implement code splitting using dynamic imports (React.lazy and Suspense) to break
down the application into smaller chunks. This allows for loading only the necessary
code for a specific route or feature, reducing initial load time.
List Virtualization:
When rendering large lists, use libraries like react-window or react-virtualized to
render only the visible items. This technique significantly improves performance by
minimizing the number of DOM elements rendered.
Avoiding Inline Function Definitions:
Define functions outside the render method to prevent unnecessary re-renders. Inline
functions create a new function instance on each render, potentially triggering re-
renders of child components.
Properly Using Keys:
When rendering lists, ensure each item has a unique and stable key. Using array
indexes as keys can lead to incorrect rendering and performance issues when the list
changes.
Minimizing State Updates:
Frequent state updates can trigger multiple re-renders. Minimize the use
of setState and consider techniques like batching state updates or
using useReducer for complex state logic.
Optimize API Calls:
Employ strategies such as caching, pagination, and batching requests to reduce the
overhead of data fetching.
Production Build:
Always deploy the production build of the application. This build is optimized for
performance and strips away unnecessary development features.
Using React.Fragment – When working with React, there are cases where we need to
render multiple elements or return a group of related items. Using additional div to wrap
will fix this, but it comes with a problem. Because we are adding an extra node to the
DOM, which is totally not useful. In cases like this, where we have the child component
which is enclosed within a parent component. Here we encounter this problem. Let’s
solve this by using React Fragment, which will help not to add any additional node to the
DOM.
Use of production build – Another way of optimizing a React app is by making sure you
bundle your app for production before deploying. By default, the app is in development
mode, which means React will include helpful warnings which come with it. This method
is useful while you are developing a ReactJS application, but it creates a problem that
your app size is large and responses are slower than usual. If the project is built with
create-react-app, This can be fixed by running npm run build before the deployment,
which will create a production-ready build of your app in a build/ folder that can be then
deployed. This can make sure that your app is in either development or production mode
using the React Developer Tools.
From the project directory run the code:
npm run build
This will create a production build of the ReactJS app.
Prefer component state local – Whenever a state updates in a parent component, it re-
renders the parent and its child components. Therefore, we need to make sure that re-
rendering a component only happens when it is necessary. We can achieve this by making
it local to that part of the code.
Memorizing React components – React. Memo is a great way of optimizing
performance as it helps cache functional components.
Memorization in general is an optimization technique used primarily to speed up
computer programs by storing the results of expensive function calls and returning the
cached result when the same inputs occur again. Whenever a function is rendered using
this technique, it saves the output in memory, and the next time the function with the
same arguments is called it returns the saved output without executing the function again.
Windowing or list virtualization – Windowing or List virtualization is a concept of only
rendering or writing the visible portion in the current “window” to the DOM. The number
of items rendered for the first time is smaller than the original one. The items which are
not rendered in the first small window will load when scrolling down to it. The DOM
nodes of items that exit from the current window are replaced by the new which were not
rendered the first time. This improves the performance of rendering a large list.
Creating React Application:
Step 1: Create a React application using the following command:
npx create-react-app example
Step 2: After creating your project folder i.e. example, move to it using the following
command:
cd example
Project structure: It will look like this.
Example: To demonstrate to optimize react app. Write down the following code in index.js
and App.js
React Redux is the official React binding for Redux. It allows React components to
interact with a Redux store, enabling centralized state management in React
applications. React Redux provides tools and utilities to connect React components to the
Redux store, dispatch actions, and access state data. It simplifies the process of managing
application state, especially in complex applications with many components and
interactions.
React Redux offers several key features:
Predictable state management:
Redux enforces a unidirectional data flow, making state changes predictable and easier
to debug.
Centralized store:
Redux provides a single source of truth for the application state, simplifying state
management across multiple components.
Encapsulated logic:
React Redux allows developers to encapsulate state logic and business logic separately from
UI components.
Performance optimizations:
React Redux implements performance optimizations to prevent unnecessary re-renders of
components.
Integration with React:
React Redux is designed to work seamlessly with React's component model, providing a
natural and efficient development experience. React Redux is commonly used in large-scale
React applications to manage complex state requirements. It helps to improve code
organization, maintainability, and testability.
React Redux is the official react binding for redux. It provides a predictable state
container by connecting React components to a centralized store, simplifying data
flow and enabling efficient management of application state across components.
Uses: It makes it easier to manage state and data. As the complexity of our application
increases. At the start, it is hard to understand but it helps to build complex
applications. In the beginning, it feels like a lot of work, but it is really helpful.
When diving into web development, it's important to learn the basics of React and
Redux. React that makes your code more modular and reusable. It's all about
efficiency, especially with the virtual DOM ensuring your app runs smoothly. And
then there's Redux, stepping in like a superhero for state management.
It plays seamlessly with React, handling those complex states. Together, React and
Redux not only simplify UI development but also improve the way for scalable and
maintainable applications.
Advantages
The advantages to react redux are given below:
Centralized state management system i.e. Store: React state is stored locally within a
component. To share this state with other components in the application, props are passed
to child components, or callbacks are used for parent components. Redux state, on the
other hand, is stored globally in the store. All the components of the entire application
can easily access the data directly. This centralizes all data and makes it very easy for a
component to get the state it requires. So while developing large, complex applications
with many components, the Redux store is highly preferred.
Performance Optimizations: By default, whenever a component is updated, React re-
renders all the components inside that part of the component tree. In such a case when
the data for a given component hasn’t changed, these re-renders are wasted (cause the UI
output displayed on the screen would remain the same). Redux store helps in improving
the performance by skipping such unnecessary re-renders and ensuring that a given
component re-renders only when its data has actually changed.
Pure reducer functions: A pure function is defined as any function that doesn’t alter
input data, doesn’t depend on the external state, and can consistently provide the same
output for the same input. As opposed to React, Redux depends on such pure functions.
It takes a given state (object) and passes it to each reducer in a loop. In case of any data
changes, a new object is returned from the reducer (re-rendering takes place). However,
the old object is returned if there are no changes (no re-rendering).
Storing long-term data: Since data stored in redux persists until page refresh, it is
widely used to store long-term data that is required while the user navigates the
application, such as, data loaded from an API, data submitted through a form, etc. On the
other hand, react is suitable for storing short-term data that is likely to change quickly
(form inputs, toggles, etc.)
Great supportive community Since redux has a large community of users, it becomes
easier to learn about best practices, get help when stuck, reuse your knowledge across
different applications. Also, there are a number of extensions for redux that help in
simplifying the code logic and improving the performance.
│ ├── pages/ # Top-level route components (if not using feature folders)
│ ├── routes/ # Route definitions
│ ├── hooks/ # Custom hooks
│ ├── context/ # React context definitions
│ ├── services/ # API services or other business logic
│ ├── utils/ # Utility functions
│ ├── store/ # Redux store (or other state management)
│ ├── App.tsx # Root component
│ └── main.tsx # Entry point
├── .env # Environment variables
├── package.json
├── tsconfig.json # If using TypeScript
└── README.md
Redux Architecture
React Redux is a library that connects your React components to the Redux store, which
manages your application's global state. It's essential for building scalable and maintainable
React applications where you need to share data across components efficiently.
Core Concepts:
Store: A single object that holds the entire application state.
Actions: Plain JavaScript objects that describe an event that has occurred in the
application, triggering a state update.
Reducers: Pure functions that specify how the application's state changes in response to
dispatched actions.
Dispatch: A function that provides access to the store, allowing components to dispatch
actions.
Selectors: Functions that extract data from the store.
Predictable State: Redux ensures a clear and predictable flow of data, making it easier to
debug and maintain applications.
Centralized State Management: The single store provides a central place to manage the
application's state, simplifying complex data management.
Improved Scalability: Redux's structured approach makes it easier to scale applications
as they grow.
Enhanced Testability: The predictable state and pure functions of Redux make it easier to test
application logic.
Installation and Setup:
Install Redux: Run npm install redux.
Install React Redux: Run npm install react-redux.
Redux Toolkit (Optional): Consider installing Redux Toolkit for a streamlined Redux
experience, according to a post on Medium. Run npm install @reduxjs/toolkit.
Create a Redux Store: Define your initial state, reducers, and create the store using Redux.
Connect React Components: Use React Redux hooks (useSelector and useDispatch) to
connect your components to the store and access/update state.
In essence, React Redux provides a bridge between your React components and Redux,
enabling you to manage and interact with your application's global state effectively, says a
video on YouTube.
Connecting a React component to Redux using connect()
1. Import connect from react-redux:
import { connect } from 'react-redux';
2. Define mapStateToProps:
This function takes the Redux state and maps the parts of it you want as props in your
component.
const mapStateToProps = (state) => ({counter: state.counter,});
3. Define mapDispatchToProps (optional):
This function maps action creators to props so you can dispatch actions from your
component.
const mapDispatchToProps = (dispatch) => ({
increment: () => dispatch({ type: 'INCREMENT' }),});
4. Create your component:
const Counter = ({ counter, increment }) => (<div>
<p>Count: {counter}</p>
<button onClick={increment}>Increment</button>
</div>
);
5. Connect the component to Redux:
export default connect(mapStateToProps, mapDispatchToProps)(Counter);