React FAQ
React FAQ
React is a JavaScript library created for building fast and interactive user interfaces for web and mobile applications. It is an open-
source, component-based, front-end library responsible only for the application view layer.
The main objective of ReactJS is to develop User Interfaces (UI) that improves the speed of the apps. It uses virtual DOM (JavaScript
object), which improves the performance of the app. The JavaScript virtual DOM is faster than the regular DOM. We can use ReactJS
on the client and server-side as well as with other frameworks. It uses component and data patterns that improve readability and
helps to maintain larger apps.
Reference:
Unlike browser DOM elements, React elements are plain objects and are cheap to create. React DOM takes care of updating the
DOM to match the React elements. The reason for this is that JavaScript is very fast and it is worth keeping a DOM tree in it to
speedup its manipulation.
It relies on a virtual-dom to know what is really changing in UI and will re-render only what has really changed, hence
better performance wise
JSX makes components/blocks code readable. It displays how components are plugged or combined with.
React data binding establishes conditions for creation dynamic applications.
Prompt rendering. Using comprises methods to minimise number of DOM operations helps to optimise updating process
and accelerate it. Testable. React native tools are offered for testing, debugging code.
SEO-friendly. React presents the first-load experience by server side rendering and connecting event-handlers on the side
of the user:
o React.renderComponentToString is called on the server.
o React.renderComponent() is called on the client side.
o React preserves markup rendered on the server side, attaches event handlers.
Limitations:
Learning curve. Being not full-featured framework it is requered in-depth knowledge for integration user interface free
library into MVC framework.
View-orientedness is one of the cons of ReactJS. It should be found 'Model' and 'Controller' to resolve 'View' problem.
Not using isomorphic approach to exploit application leads to search engines indexing problems.
↥
The view is a result of the application state. State can only change when actions happen. When actions happen, the state is updated.
One-way data binding provides us with some key advantages
In React, a state is always owned by one component. Any changes made by this state can only affect the components below it, i.e
its children. Changing state on a component will never affect its parent or its siblings, only the children will be affected. This is the
main reason that the state is often moved up in the component tree so that it can be shared between the components that need to
access it.
↥
// App.js
const employee = {
emp_id: 10,
name: "Nakul Agate",
email: "[email protected]"
};
When used, destructuring does not modify an object or array but rather copies the desired items from those data structures into
variables. These new variables can be accessed later on in a React component.
Example:
/**
* Destructuring in React
*/
import React from "react";
return (
<>
<button onClick={() => setcounter(counter + 1)}> Increment </button>
<button onClick={() => setcounter(counter > 0 ? counter - 1 : 0)}>
Decrement
</button>
<h2>Result: {counter}</h2>
</>
);
}
When an element type starts with a lowercase letter, it refers to a built-in component like or and results in a
string <div> or <span> passed to React.createElement. Types that start with a capital letter like compile
to React.createElement(Foo) and correspond to a component defined or imported in your JavaScript file.
Example:
Benefits:
It's a tiny bit faster and has less memory usage (no need to create an extra DOM node). This only has a real benefit on very
large and/or deep trees, but application performance often suffers from death by a thousand cuts. This is one cut less.
Some CSS mechanisms like Flexbox and CSS Grid have a special parent-child relationship, and adding divs in the middle
makes it hard to keep the desired layout while extracting logical components.
The DOM inspector is less cluttered.
Manipulating DOM is slow, but manipulating Virtual DOM is fast as nothing gets drawn on the screen. So each time there is a
change in the state of our application, virtual DOM gets updated first instead of the real DOM.
2. Virtual DOM:
Virtual DOM is any kind of representation of a real DOM. Virtual DOM is about avoiding unnecessary changes to the DOM, which are
expensive performance-wise, because changes to the DOM usually cause re-rendering of the page. It allows to collect several
changes to be applied at once, so not every single change causes a re-render, but instead re-rendering only happens once after a set
of changes was applied to the DOM.
3. Shadow DOM:
Shadow DOM is mostly about encapsulation of the implementation. A single custom element can implement more-or-less complex
logic combined with more-or-less complex DOM. Shadow DOM refers to the ability of the browser to include a subtree of DOM
elements into the rendering of a document, but not into the main document DOM tree.
Difference:
The virtual DOM creates an additional DOM. The shadow DOM simply hides implementation details and provides isolated scope for
web components.
# 2. REACT SETUP
Requirements:
The Create React App is maintained by Facebook and can works on any platform, for example, macOS, Windows, Linux, etc. To
create a React Project using create-react-app, you need to have installed the following things in your system.
Installation:
Output:
Running any of these commands will create a directory called my-app inside the current folder. Inside that directory, it will generate
the initial project structure and install the transitive dependencies:
my-app
├── README.md
├── node_modules
├── package.json
├── .gitignore
├── public
│ ├── favicon.ico
│ ├── index.html
│ ├── logo192.png
│ ├── logo512.png
│ ├── manifest.json
│ └── robots.txt
└── src
├── App.css
├── App.js
├── App.test.js
├── index.css
├── index.js
├── logo.svg
├── serviceWorker.js
└── setupTests.js
Reference:
Below are the list of some of the features provided by create react app.
function App() {
return (
<div className="App">
<header className="App-header">
<h1>Hello world app</h1>
</header>
</div>
);
}
export default App;
npm start
On the local server (http://localhost:3000) you can see a simple React app displaying a "hello world" message. The next step is to
make this app production-ready for deployment. Inside the root directory run the following command:
This creates a build directory inside the root directory, which bundles your React app and minifies it into simple HTML, CSS, and
JavaScript files. This build folder serves your app via a simple en point, index.html, where your entire React app resides. Running
your app via a remote server means running this index.html file on the server.
↥
One common way to structure projects is to locate CSS, JS, and tests together inside folders grouped by feature or route.
common/
Avatar.js
Avatar.css
APIUtils.js
APIUtils.test.js
feed/
index.js
Feed.js
Feed.css
FeedStory.js
FeedStory.test.js
FeedAPI.js
profile/
index.js
Profile.js
ProfileHeader.js
ProfileHeader.css
ProfileAPI.js
Another popular way to structure projects is to group similar files together, for example:
api/
APIUtils.js
APIUtils.test.js
ProfileAPI.js
UserAPI.js
components/
Avatar.js
Avatar.css
Feed.js
Feed.css
FeedStory.js
FeedStory.test.js
Profile.js
ProfileHeader.js
ProfileHeader.css
This will install the plugin we need, and in our ESLint config file, we just need a few extra lines.
"extends": [
"eslint:recommended",
"plugin:react/recommended"
]
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject",
"lint": "eslint src/**/*.js src/**/*.jsx"
}
2. eslint-plugin-jsx-a11y:
It will help fix common issues with accessibility. As JSX offers slightly different syntax to regular HTML, issues with alt text
and tabindex, for example, will not be picked up by regular plugins.
↥
The browserslist configuration controls the outputted JavaScript so that the emitted code will be compatible with the browsers
specified.
Example:
// package.json
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
Babel is a JS transpiler that converts new JS code into old ones. It is a very flexible tool in terms of transpiling. One can easily add
presets such as es2015, es2016, es2017, or env; so that Babel compiles them to ES5. Babel allows us to have a clean, maintainable code
using the latest JS specifications without needing to worry about browser support.
2. Webpack:
Webpack is a modular build tool that has two sets of functionality — Loaders and Plugins. Loaders transform the source code of a
module. For example, style-loader adds CSS to DOM using style tags. sass-loader compiles SASS files to CSS. babel-loader transpiles
JS code given the presets. Plugins are the core of Webpack. They can do things that loaders can't. For example, there is a plugin
called UglifyJS that minifies and uglifies the output of webpack.
3. create-react-app:
create-react-app, a popular tool that lets you set up a React app with just one command. You don't need to get your hands dirty
with Webpack or Babel because everything is preconfigured and hidden away from you.
/**
* React vs ReactDOM
*/
import { createRoot } from "react-dom/client";
root.render(<App />);
Q. What is ReactDOM?
ReactDOM is a package that provides DOM specific methods that can be used at the top level of a web app to enable an efficient
way of managing DOM elements of the web page.
ReactDOM provides the developers with an API containing the following methods
render()
findDOMNode()
unmountComponentAtNode()
hydrate()
createPortal()
1. render():
Render a React element into the DOM in the supplied container and return a reference to the component (or returns null for
stateless components). If the React element was previously rendered into container, this will perform an update on it and only
mutate the DOM as necessary to reflect the latest React element. If the optional callback is provided, it will be executed after the
component is rendered or updated.
⚝
2. hydrate():
This method is equivalent to the render() method but is implemented while using server-side rendering. This function attempts to
attach event listeners to the existing markup and returns a reference to the component or null if a stateless component was
rendered.
⚝
3. unmountComponentAtNode():
ReactDOM.unmountComponentAtNode(container)
This function is used to unmount or remove the React Component that was rendered to a particular container. It returns true if a
component was unmounted and false if there was no component to unmount.
4. findDOMNode():
ReactDOM.findDOMNode(component)
If this component has been mounted into the DOM, this returns the corresponding native browser DOM element. This method is
useful for reading values out of the DOM, such as form field values and performing DOM measurements.
5. createPortal():
ReactDOM.createPortal(child, container)
createPortal allow us to render a component into a DOM node that resides outside the current DOM hierarchy of the parent
component.
# 3. REACT JSX
Q. What is JSX?
JSX ( JavaScript Expression ) allows us to write HTML elements in JavaScript and place them in the DOM without
any createElement() or appendChild() methods. JSX converts HTML tags into react elements. React uses JSX for templating instead
of regular JavaScript. It is not necessary to use it, however, following are some pros that come with it.
When JSX compiled, they actually become regular JavaScript objects. For instance, the code below:
will be compiled to
Example:
constructor(props) {
super(props);
this.state = {
userContent: `JSX prevents Injection Attacks Example
<script src="http://example.com/malicious-script.js></script>`
};
}
render() {
return (
<div>User content: {this.state.userContent}</div>
);
}
}
// Output
User content: JSX prevents Injection Attacks Example
<script src="http://example.com/malicious-script.js></script>
render() {
return null
}
render() {
return []
}
render() {
return <React.Fragment></React.Fragment>
}
render() {
return <></>
}
Note that React can also run on the server side so, it will be possible to use it in such a way that it doesn't involve any DOM
modifications (but maybe only the virtual DOM computation).
React comments:
function App() {
/*
* multi
* line
* comment
**/
return (
<h1>My Application</h1>
);
}
JSX comments:
Example:
const headings = (
<div id = "outermost-element">
<h1>I am a heading </h1>
<h2>I am also a heading</h2>
</div>
)
/**
* Loop inside JSX
*/
const animals = [
{ id: 1, animal: "Dog" },
{ id: 2, animal: "Bird" },
{ id: 3, animal: "Cat" },
{ id: 4, animal: "Mouse" },
{ id: 5, animal: "Horse" }
];
<div />
<div></div>
<div>{false}</div>
<div>{null}</div>
<div>{undefined}</div>
<div>{true}</div>
If you want a value like false, true, null, or undefined to show in the output, you have to convert it to a string first.
<div>{String(true)}</div>
<div>{String(false)}</div>
<div>{String(undefined)}</div>
<div>{String(null)}</div>
In the output, this will render true, false, undefined, and null respectively.
⚝
function App() {
return (
<div
dangerouslySetInnerHTML={{
__html: "<h2>This text is set using dangerouslySetInnerHTML</h2>"
}}
></div>
);
}
return (
<div className="full tr">
<button className="product--cart-button">Add to Cart</button>
</div>
)
}
2. Ternary Display:
When you need to control whether one element vs. another is displayed, or even one element vs. nothing at all (null), you can use
the ternary operator embedded inside of a larger portion of JSX.
<div className="half">
<p>{description}</p>
{remaining === 0 ? (
<span className="product-sold-out">Sold Out</span>
) : (
<span className="product-remaining">{remaining} remaining</span>
)}
</div>
In this case, if there are no products remaining, we will display "Sold Out"; otherwise we will display the number of products
remaining.
3. Shortcut Display:
It involves using a conditional inside of your JSX that looks like checkIfTrue && <span>display if true</span> . Because if
statements that use && operands stop as soon as they find the first value that evaluates to false, it won't reach the right side (the JSX)
if the left side of the equation evaluates to false.
<h2>
<span className="product--title__large">{nameFirst}</span>
{nameRest.length > 0 && (
<span className="product--title__small">{nameRest.join(" ")}</span>
)}
</h2>
# 4. REACT COMPONENTS
1. Stateless Component:
The above example shows a stateless component named ExampleComponent which is inserted in the <App/> component.
The ExampleComponent just comprises of a <h1> element. Although the Stateless component has no state, it still receives data via
props from a parent component.
2. Stateful Component:
return (
<input type="text" value={email} onChange={changeEmailHandler} />
);
}
The above example shows a stateful component named ExampleComponent which is inserted in the <App/> component.
The ExampleComponent contains a <input>. First of all, in the ExampleComponent, we need to assign defaultEmail by props to a
local state by a useState() hook in ExampleComponent.
Next, we have to pass email to value property of a input tag and pass a function changeEmailHandler to an onChange() event for a
purpose keeping track of the current value of the input.
↥
For example, this is a presentational component. It gets data from its props, and just focuses on showing an element
/**
* Presentational Component
*
**/
const Users = props => (
<ul>
{props.users.map(user => (
<li>{user}</li>
))}
</ul>
)
On the other hand this is a container component. It manages and stores its own data, and uses the presentational component to
display it.
/**
* Container Component
*
**/
class UsersContainer extends React.Component {
constructor() {
this.state = {
users: []
}
}
componentDidMount() {
axios.get('/users').then(users =>
this.setState({ users: users }))
)
}
render() {
return <Users users={this.state.users} />
}
}
By using default you express that's going to be member in that module which would be imported if no specific member name is
provided. You could also express you want to import the specific member called DangerButton by doing so: import { DangerButton
} from './comp/danger-button'; in this case, no default is needed
↥
In this example, we loop through every character in the string, replacing spaces as they occur. Just looking at the code, it doesn't say
much. Imperative requires lots of comments in order to understand code. Whereas in the declarative program, the syntax itself
describes what should happen and the details of how things happen are abstracted way.
2. Declarative programming:
It is a programming paradigm that expresses the logic of a computation without describing its control flow.
Example:
React is declarative. Here, the Welcome component describes the DOM that should be rendered. The render function uses the
instructions declared in the component to build the DOM, abstracting away the details of how the DOM is to be rendered. We can
clearly see that we want to render our Welcome component into the element with the ID of 'target'.
It is a simple object that describes a DOM node and its attributes or properties. It is an immutable description object and you can
not apply any methods on it.
2. React Component:
It is a function or class that accepts an input and returns a React element. It has to keep references to its DOM nodes and to the
instances of the child components.
function Message() {
return <h2>React Component Example!</h2>;
}
ReactDOM.render(<Message />, document.getElementById('app'));
1. Element Variables:
You can use variables to store elements. This can help you conditionally render a part of the component while the rest of the output
doesn't change.
function LogInComponent(props) {
const isLoggedIn = props.isLoggedIn;
if (isLoggedIn) {
return <UserComponent />;
}
return <GuestComponent />;
}
ReactDOM.render(
<LogInComponent isLoggedIn={false} />,
document.getElementById('root')
);
/**
* Conditionally add attributes
*/
import React from "react";
return (
<button onClick={greet} disabled={"happy" === mood ? false : true}>
Say Hi
</button>
);
}
The React shouldComponentUpdate() method return true if it needs to re-render or false to avoid being re-render.
Syntax:
shouldComponentUpdate(nextProps, nextState){ }
Example:
/**
* Prevent a component from rendering
*/
export default class App extends React.Component {
constructor() {
super();
this.state = {
countOfClicks: 0
};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState({
countOfClicks: this.state.countOfClicks + 1
});
}
shouldComponentUpdate(nextProps, nextState) {
console.log("this.state.countOfClicks", this.state.countOfClicks);
console.log("nextState.countOfClicks", nextState.countOfClicks);
return true;
}
render() {
return (
<div>
<h2>shouldComponentUpdate Example</h2>
<p>Count of clicks: <b>{this.state.countOfClicks}</b></p>
<button onClick={this.handleClick}>CLICK ME</button>
</div>
);
}
}
Example:
/**
* StrictMode
*/
import { StrictMode } from "react";
import MyComponent from "./MyComponent";
React StrictMode, in order to be efficient and avoid potential problems by any side-effects, needs to trigger some methods and
lifecycle hooks twice. These are:
Benefits of StrictMode:
/**
* setState() in unmounted component
*/
import React, { Component } from "react";
import axios from "axios";
constructor(props) {
super(props);
this.state = {
news: []
};
}
componentDidMount() {
this._isMounted = true;
axios
.get("https://hn.algolia.com/api/v1/search?query=react")
.then((result) => {
if (this._isMounted) {
this.setState({
news: result.data.hits
});
}
});
}
componentWillUnmount() {
this._isMounted = false;
}
render() {
return (
<ul>
{this.state.news.map((topic) => (
<li key={topic.objectID}>{topic.title}</li>
))}
</ul>
);
}
}
Here, even though the component got unmounted and the request resolves eventually, the flag in component will prevent to set the
state of the React component after it got unmounted.
↥
Q. What is Lifting State Up in ReactJS?
The common approach to share state between two components is to move the state to common parent of the two components.
This approach is called as lifting state up in React.js. With the shared state, changes in state reflect in relevant components
simultaneously.
Example:
The App component containing PlayerContent and PlayerDetails component. PlayerContent shows the player name buttons.
PlayerDetails shows the details of the in one line.
The app component contains the state for both the component. The selected player is shown once we click on the one of the player
button.
/**
* Lifting State Up
*/
import React from "react";
import PlayerContent from "./PlayerContent";
import PlayerDetails from "./PlayerDetails";
/**
* PlayerContent
*/
import React, { Component } from "react";
/**
* PlayerDetails
*/
import React, { Component } from "react";
The special thing about children is that React provides support through its ReactElement API and JSX. XML children translate
perfectly to React children!
Example:
/**
* Children in React
*/
const Picture = (props) => {
return (
<div>
<img src={props.src}/>
{props.children}
</div>
)
}
This component contains an <img> that is receiving some props and then it is displaying {props.children}. Whenever this
component is invoked {props.children} will also be displayed and this is just a reference to what is between the opening and
closing tags of the component.
/**
* App.js
*/
render () {
return (
<div className='container'>
<Picture key={picture.id} src={picture.src}>
{/** what is placed here is passed as props.children **/}
</Picture>
</div>
)
}
Internally they are built to operate on a set of data that is passed in through children instead of props. Behind the scenes they make
use of React's lower level API such as React.children.map(), and React.cloneElement(). Using these methods, the component is able
to express itself in such a way that promotes patterns of composition and extensibility.
Example:
function App() {
return (
<Menu>
<MenuButton>
Actions <span aria-hidden>▾</span>
</MenuButton>
<MenuList>
<MenuItem onSelect={() => alert('Download')}>Download</MenuItem>
<MenuItem onSelect={() => alert('Copy')}>Create a Copy</MenuItem>
<MenuItem onSelect={() => alert('Delete')}>Delete</MenuItem>
</MenuList>
</Menu>
)
}
In this example, the <Menu> establishes some shared implicit state. The <MenuButton>, <MenuList>, and <MenuItem> components each
access and/or manipulate that state, and it's all done implicitly. This allows you to have the expressive API you're looking for.
↥
After the introduction of React Hooks, writing functional components has become the standard way of writing React components in
modern applications.
Example:
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
ReactDOM.render(
element,
document.getElementById('root')
);
Example:
ReactDOM.render(
element,
document.getElementById('root')
);
renderTableHeader() {
let header = Object.keys(this.state.employees[0])
return header.map((key, index) => {
return <th key={index}>{key.toUpperCase()}</th>
})
}
renderTableData() {
return this.state.employees.map((employee, index) => {
const { id, name, age, email } = employee
return (
<tr key={id}>
<td>{id}</td>
<td>{name}</td>
<td>{email}</td>
</tr>
)
})
}
render() {
return (
<div>
<h1 id='title'>React Dynamic Table</h1>
<table id='employees'>
<tbody>
<tr>{this.renderTableHeader()}</tr>
{this.renderTableData()}
</tbody>
</table>
</div>
)
}
}
return (
<div className="warning">
Warning!
</div>
);
}
handleToggleClick() {
this.setState(state => ({
showWarning: !state.showWarning
}));
}
render() {
return (
<div>
{ /* Prevent component render if value of the prop is false */}
<WarningBanner warn={this.state.showWarning} />
<button onClick={this.handleToggleClick}>
{this.state.showWarning ? 'Hide' : 'Show'}
</button>
</div>
);
}
}
ReactDOM.render(
<Page />,
document.getElementById('root')
);
The literal difference is that one has state, and the other does not. That means the stateful components are keeping track of
changing data, while stateless components print out what is given to them via props, or they always render the same thing.
function welcome(props) {
return <h1>This is a React Functional Component</h1>;
}
Class components need to extend the component from Functional components are like normal functions which
"React.Component" and create a render function that returns the take "props" as the argument and return the required
required element. element.
They are also known as stateful components. They are also known as stateless components.
They implement logic and the state of the component. They accept some kind of data and display it in the UI.
Lifecycle methods can be used inside them. Lifecycle methods cannot be used inside them.
It needs to store state therefore constructors are used. Constructors are not used in it.
It has to have a "render()" method inside that. It does not require a render method.
Here, super(props) would call the React.Component constructor passing in props as the argument.
↥
A React Element is just a plain old JavaScript Object without own methods. It has essentially four properties:
A React Element is not an instance of a React Component. It is just a simplified "description" of how the React Component Instance
to be created should look like.
A React Component is used by extending React.Component. If a React Component is instantiated it expects a props Object and
returns an instance, which is referred to as a React Component Instance.
A React Component can contain state and has access to the React Lifecycle methods. It must have at least a render method, which
returns a React Element(-tree) when invoked.
Example:
/**
* React Component Instances
*/
import React from 'react'
import ReactDOM from 'react-dom'
render() {
const another_element = <div>Hello, World!</div>
console.log('This is also an element:' + another_element)
return another_element
}
}
ReactDOM.render(element, document.getElementById('root'));
shouldComponentUpdate(nextProps, nextState) {
console.log(nextProps, nextState)
console.log(this.props, this.state)
return false
}
The shouldComponentUpdate() method is the first real life cycle optimization method that we can leverage in React. It checks the
current props and state, compares it to the next props and state and then returns true if they are different, or false if they are the
same. This method is not called for the initial render or when forceUpdate() is used.
↥
Purpose of render():
React renders HTML to the web page by using a function called render().
The purpose of the function is to display the specified HTML code inside the specified HTML element.
In the render() method, we can read props and state and return our JSX code to the root component of our app.
In the render() method, we cannot change the state, and we cannot cause side effects ( such as making an HTTP request to
the webserver).
/**
* render() function
*
* React v18.0.0
*/
import React from "react";
import { createRoot } from "react-dom/client";
These methods are called in the following order when an instance of a component is being created and inserted into the DOM:
constructor()
getDerivedStateFromProps()
render()
componentDidMount()
2. Updating:
The next phase in the lifecycle is when a component is updated. A component is updated whenever there is a change in the
component's state or props.
React has five built-in methods that gets called, in this order, when a component is updated:
getDerivedStateFromProps()
shouldComponentUpdate()
render()
getSnapshotBeforeUpdate()
componentDidUpdate()
3. Unmounting:
The next phase in the lifecycle is when a component is removed from the DOM, or unmounting as React likes to call it.
componentWillUnmount()
The componentDidMount() lifecycle hook can be used with class components. Any actions defined within
a componentDidMount() lifecycle hook are called only once when the component is first mounted.
Example:
The useEffect() hook can be used with function components. The useEffect() hook is more flexible than the lifecycle methods used
for class components. It receives two parameters:
The value passed as the second argument controls when the callback is executed:
If the second parameter is undefined, the callback is executed every time that the component is rendered.
If the second parameter contains an array of variables, then the callback will be executed as part of the first render cycle
and will be executed again each time an item in the array is modified.
If the second parameter contains an empty array, the callback will be executed only once as part of the first render cycle.
Example:
return <div>Homepage</div>
}
Here, shouldComponentUpdate() will return false if the props its receiving are equal to the props it already has. And because the
AnimalTable is receiving just a List of string IDs, a change in the adoption status won't cause AnimalTable to receive a different set of
IDs.
↥
The componentDidMount() and useEffect() run after the mount. However useEffect() runs after the paint has been committed to the
screen as opposed to before. This means we would get a flicker if needed to read from the DOM, then synchronously set state to
make new UI.
The useLayoutEffect() was designed to have the same timing as componentDidMount(). So useLayoutEffect(fn, []) is a much
closer match to componentDidMount() than useEffect(fn, []) -- at least from a timing standpoint.
/**
* componentDidMount() in Class Component
*/
import React, { Component } from "react";
/**
* useEffect() in Functional Component
*/
import React, { useEffect } from "react";
The first argument is a callback that will be fired after browser layout and paint. Therefore it does not block the painting
process of the browser.
The second argument is an array of values (usually props).
If any of the value in the array changes, the callback will be fired after every render.
When it is not present, the callback will always be fired after every render.
When it is an empty list, the callback will only be fired once, similar to componentDidMount.
If you give each component a unique key prop, React can use the key change to infer that the component has actually been
substituted and will create a new one from scratch, giving it the full component lifecycle.
renderContent() {
if (this.state.activeItem === 'item-one') {
return (
<Content title="First" key="first" />
)
} else {
return (
<Content title="Second" key="second" />
)
}
}
The componentDidMount() is executed after the first render only on the client side. This is where AJAX requests and DOM or state
updates should occur. This method is also used for integration with other JavaScript frameworks and any functions with delayed
execution such as setTimeout() or setInterval().
Example:
constructor(props) {
super(props)
this.state = {
data: 'Alex Belfort'
}
}
getData(){
setTimeout(() => {
console.log('Our data is fetched')
this.setState({
data: 'Hello Alex'
})
}, 1000)
}
componentDidMount() {
this.getData()
}
render() {
return (
<div>
{this.state.data}
</div>
)
}
}
componentWillMount()
The componentWillMount() method is executed before rendering, on both the server and the client
side. componentWillMount() method is the least used lifecycle method and called before any HTML element is rendered. It is useful
when we want to do something programatically right before the component mounts.
Example:
constructor(props) {
super(props)
this.state = {
data: 'Alex Belfort'
}
}
componentWillMount() {
console.log('First this called')
}
getData() {
setTimeout(() => {
console.log('Our data is fetched')
this.setState({
data: 'Hello Alex'
})
}, 1000)
}
componentDidMount() {
this.getData()
}
render() {
return (
<div>
{this.state.data}
</div>
)
}
}
↥
Q. Is it good to use setState() in
componentWillMount() method?
Avoid async initialization in componentWillMount().
componentWillMount() is invoked immediately before mounting occurs. It is called before render(), therefore setting state in this
method will not trigger a re-render. Avoid introducing any side-effects or subscriptions in this method.
Make async calls for component initialization in componentDidMount() instead of componentWillMount()
function componentDidMount() {
axios.get(`api/messages`)
.then((result) => {
const messages = result.data
console.log("COMPONENT WILL Mount messages : ", messages);
this.setState({
messages: [...messages.content]
})
})
}
If we pass an empty array as the second argument, it tells useEffect to fire on component load. This is the only time it will fire.
If you add a return function inside the useEffect() function, it is triggered when a component unmounts from the DOM.
Example:
/**
* React Pure Component
*/
import React from "react";
render() {
return <b>Array Length is: {this.state.userArray.length}</b>;
}
}
Example:
Example:
render() {
return (
<div>
<h1>Move the mouse around!</h1>
{/* define the render function as instance method */}
<Mouse render={this.renderTheCat} />
</div>
);
}
}
On the other hand, we should not use PureComponent() as a base component if:
Higher-Order Components are not part of the React API. They are the pattern that emerges from React's compositional nature. The
component transforms props into UI, and a higher-order component converts a component into another component. The examples
of HOCs are Redux's connect and Relay's createContainer.
/**
* Higher Order Component
*/
import React, { Component } from "react";
/**
* App.js
*/
import React, { Component } from "react";
import Hoc from "./HOC";
export default class App extends Component {
render() {
return <h2>Higher Order Component!</h2>;
}
}
App = Hoc(App);
Note:
Importantly they provided a way to reuse code when using ES6 classes.
No longer have method name clashing if two HOC implement the same one.
It is easy to make small reusable units of code, thereby supporting the single responsibility principle.
Apply multiple HOCs to one component by composing them. The readability can be improve using a compose function
like in Recompose.
Problems:
Boilerplate code like setting the displayName with the HOC function name e.g. (withHOC(Component)) to help with
debugging.
Ensure all relevant props are passed through to the component.
Hoist static methods from the wrapped component.
It is easy to compose several HOCs together and then this creates a deeply nested tree making it difficult to debug.
Props Proxy
Inheritance Inversion
1. Props Proxy:
In this approach, the render method of the HOC returns a React Element of the type of the WrappedComponent. We also pass
through the props that the HOC receives, hence the name Props Proxy.
Example:
function ppHOC(WrappedComponent) {
return class PP extends React.Component {
render() {
return <WrappedComponent {...this.props}/>
}
}
}
Manipulating props
Accessing the instance via Refs
Abstracting State
Wrapping the WrappedComponent with other elements
2. Inheritance Inversion:
Inheritance Inversion allows the HOC to have access to the WrappedComponent instance via this keyword, which means it has
access to the state, props, component lifecycle hooks and the render method.
Example:
function iiHOC(WrappedComponent) {
return class Enhancer extends WrappedComponent {
render() {
return super.render()
}
}
}
/**
* Inheritance Inversion
*/
class Welcome extends React.Component {
render() {
return (
<div> Welcome {his.props.user}</div>
)
}
}
When we return the Wrapped Component we have the possibility to manipulate props and to abstract state, even passing state as a
prop into the Wrapped Component.
We can create props passed to the component using props proxy pattern as below
const propsProxyHOC = (WrappedComponent) => {
Manipulating props
Accessing the instance via Refs (be careful, avoid using refs)
Abstracting State
Wrapping/Composing the WrappedComponent with other elements
Example:
render() {
return <Target {...this.props} uuid={this.uid} />;
}
};
}
@withUniqueId
class UniqueIdComponent extends React.Component {
render() {
return <div>Generated Unique ID is: {this.props.uuid}</div>;
}
}
Note: Decorators are an experimental feature in React that may change in future releases.
Example:
function withSubscription(WrappedComponent) {
WithSubscription.displayName = `WithSubscription(${getDisplayName(WrappedComponent)})`;
return WithSubscription;
}
function getDisplayName(WrappedComponent) {
return WrappedComponent.displayName || WrappedComponent.name || 'Component';
}
React.lazy is a function that lets you load components lazily through what is called code splitting without help from any external
libraries. It makes possible for us to dynamically import components but they are rendered like regular components. This means that
the bundle containing the component will only be loaded when the component is rendered.
React.lazy() takes a function that returns a promise as it's argument, the function returns a promise by calling import() to load the
content. The returned Promise resolves to a module with a default containing the React Component.
// Without Lazy
import MyComponent from './MyComponent';
// With Lazy
const MyComponent = React.lazy(() => import('./MyComponent'));
2. SUSPENSE:
React.Suspense is a component that can be used to wrap lazy components. A React.Suspense takes a fallback prop that can be any
react element, it renders this prop as a placeholder to deliver a smooth experience and also give user feedback while the lazy
component is being loaded.
/**
* Suspense
*/
import React, { Suspense } from 'react';
Example:
/**
* React Lazy Loading Routes
*/
import React, { Suspense, lazy } from "react";
import { Switch, BrowserRouter as Router, Route, Link } from "react-router-dom";
# 5. REACT PROPS
Props are immutable so we cannot modify the props from inside the component. These attributes are available in the class
component as this.props and can be used to render dynamic data in our render method.
Example:
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
function sum(a, b) {
return a + b;
}
Such functions are called pure because they do not attempt to change their inputs, and always return the same result for the same
inputs. All React components must act like pure functions with respect to their props. A component should only manage its own
state, but it should not manage its own props.
In fact, props of a component is concretely "the state of the another component (parent component)". So props must be managed
by their component owner. That's why all React components must act like pure functions with respect to their props (not to mutate
directly their props).
The defaultProps can be defined as a property on the component class itself to set the default props for the class. defaultProps is
used for undefined props, not for null props.
/**
* Default Props
*/
class MessageComponent extends React.Component {
render() {
return (
<div>Hello, {this.props.value}.</div>
)
}
}
// Default Props
MessageComponent.defaultProps = {
value: 'World'
}
ReactDOM.render(
<MessageComponent />,
document.getElementById('default')
)
ReactDOM.render(
<MessageComponent value='Folks'/>,
document.getElementById('custom')
)
⚝
↥
Example:
/**
* Access Props
*/
class App extends Component {
render() {
return (
<div>
<img
alt="React Logo"
function App() {
return <Greetings name="Nathan" age={27} occupation="Software Developer" />;
}
// Greetings Component
function Greetings(props) {
return (
<h2>
Hello! I'm {props.name}, a {props.age} years old {props.occupation}.
Pleased to meet you!
</h2>
);
}
/**
* Boolean Props
*/
const MyComponent = ({ prop1, prop2 }) => (
<div>
<div>Prop1: {String(prop1)}</div>
<div>Prop2: {String(prop2)}</div>
</div>
)
function App() {
return (
<div>
<MyComponent prop1={true} prop2={false} />
<MyComponent prop1 prop2 />
<MyComponent prop1={false} prop2 />
</div>
);
}
/**
* Props Validation
*/
import React from "react";
import PropTypes from "prop-types";
App.defaultProps = {
propBool: true,
propArray: [10, 20, 30],
propNumber: 100,
propString: "Hello React!"
};
App.propTypes = {
propBool: PropTypes.bool.isRequired,
propArray: PropTypes.array.isRequired,
propNumber: PropTypes.number,
propString: PropTypes.string
};
↥
Q. How to specify the shape of an object with
PropTypes
The PropTypes.shape() validator can be used when describing an object whose keys are known ahead of time, and may represent
different types.
Example:
/**
* PropTypes.shape()
* @param {*} props
*/
import PropTypes from "prop-types";
Output:
/**
* PropTypes
*/
import PropTypes from 'prop-types';
Component.propTypes = {
phoneNumber: PropTypes.oneOfType([
PropTypes.number,
PropTypes.string
]),
}
In simple words, render props are simply props of a component where you can pass functions. These functions need to return
elements, which will be used in rendering the components.
Example:
/**
* Render Props
*/
import React from "react";
import Wrapper from "./Wrapper";
/**
* Wrapper Component
*/
class Wrapper extends React.Component {
state = {
count: 0
};
// Increase count
increment = () => {
const { count } = this.state;
return this.setState({ count: count + 1 });
};
render() {
const { count } = this.state;
return (
<div>
{this.props.render({ increment: this.increment, count: count })}
</div>
);
}
}
Problems:
Caution using shouldComponentUpdate() as the render prop might close over data it is unaware of.
There could also be minor memory issues when defining a closure for every render. But be sure to measure first before
making performance changes as it might not be an issue for your app.
Another small annoyance is the render props callback is not so neat in JSX as it needs to be wrapped in an expression.
Rendering the result of an HOC does look cleaner.
Example:
function withMouse(Component) {
return class extends React.Component {
render() {
return (
<Mouse render={mouse => (
<Component {...this.props} mouse={mouse} />
)}/>
);
}
}
}
↥
1. Higher-order components:
Essentially HOC are similar to the decorator pattern, a function that takes a component as the first parameter and returns a new
component. This is where you apply your crosscutting functionality.
Example:
function withExample(Component) {
return function(props) {
// cross cutting logic added here
return <Component {...props} />;
};
}
2. Render Props:
A render prop is where a component's prop is assigned a function and this is called in the render method of the component. Calling
the function can return a React element or component to render.
Example:
render(){
<FetchData render={(data) => {
return <p>{data}</p>
}} />
}
The React community is moving away from HOC (higher order components) in favor of render prop components (RPC). For the most
part, HOC and render prop components solve the same problem. However, render prop components provide are gaining popularity
because they are more declarative and flexible than an HOC.
/**
* React Children Props
*/
class MyComponent extends React.Component {
render() {
return (
<div>
<h1>React Children Props Example</h1>
{this.props.children}
</div>
);
}
}
ReactDOM.render(
<MyComponent>
<p>React DOM Props</p> {/* Children Props*/}
<OtherComponent />
</MyComponent>,
document.getElementById("root")
);
Since {this.props.children} can have one element, multiple elements, or none at all, its value is respectively a single child node, an
array of child nodes or undefined. Sometimes, we want to transform our children before rendering them — for example, to add
additional props to every child. If we wanted to do that, we'd have to take the possible types of this.props.children into account.
For example, if there is only one child, we can not map it.
Example:
/**
* React Children Props
*/
export default class App extends React.Component {
render() {
return (
<div>
<b>Children ({this.props.children.length}):</b>
{this.props.children}
</div>
);
}
}
render() {
return
<div>
<h2>First Example:</h2>
<App>
<div>10</div>
<div>20</div>
<div>30</div>
</App>
<h2>Second Example:</h2>
<App>
<div>A</div>
<div>B</div>
</App>
</div>
}
}
Output
First Example:
Children (3):
10
20
30
Second Example:
Children (2):
A
B
⚝
function App() {
const props = {firstName: 'Pallav', lastName: 'Hegde'}
return <Hello {...props} />
}
When we use the ...props syntax, actaully it expand the props object from the parent component, which means all its attributes are
passed down the child component that may not need them all. This will make things like debugging harder.
Using the Spread Operator with setState() for Setting the Nested State:
this.state = {
stateObj: {
attr1: '',
attr2: '',
},
}
We can use the Spread syntax to update the nested state object.
this.setState(state => ({
person: {
...state.stateObj,
attr1: 'value1',
attr2: 'value2',
},
}))
Problem: This will to add the unknown HTML attribute flag to the DOM element.
const Sample = () => (<Spread flag={true} className="content"/>);
const Spread = (props) => (<div {...props}>Test</div>);
Solution: By creating props specifically for DOM attribute, we can safely spread.
Note:
In scenarios where you use a PureComponent, when an update happens it re-renders the component even if domProps did not change.
This is because PureComponent only shallowly compares the objects.
↥
this.state = {
records: [],
inputValue: this.props.inputValue
}
}
render() {
return <div>{this.state.inputValue}</div>
}
}
Good:
this.state = {
records: []
}
}
render() {
return <div>{this.props.inputValue}</div>
}
}
/**
* The parent component
*/
class ParentComp extends React.Component {
render() {
// The new prop to the added.
let newProp = 'red'
// Looping over the parent's entire children,
// cloning each child, adding a new prop.
return (
<div>
{React.Children.map(this.props.children,
child => {
return React.cloneElement(child,
{newProp}, null)
})}
</div>
)
}
}
/**
* The child component
*/
class MyButton extends React.Component {
render() {
return <button style =
{{ color: this.props.newProp }}>
Hello World!</button>
}
}
<ReactCSSTransitionGroup
component="div"
transitionName="example"
transitionEnterTimeout={500}
transitionLeaveTimeout={500}
>
{React.cloneElement(this.props.children, {
key: this.props.location.pathname
})}
</ReactCSSTransitionGroup>
For almost everything {this.props.children} is used. Cloning is useful in some more advanced scenarios, where a parent sends in
an element and the child component needs to change some props on that element or add things like ref for accessing the actual
DOM element.
Example:
// Parent Component
onSubmitMessage(message) {
this.setState({ message: message });
}
render() {
const { message } = this.state;
return (
<div>
<h3>Parent component</h3>
<div>The message coming from the child component is : {message}</div>
<hr />
<Child
// passing as callback function
onSubmitMessage={this.onSubmitMessage}
/>
</div>
);
}
}
// Child Component
onMessageChange(event) {
let message = event.target.value;
this.setState({ greetingMessag: message });
}
render() {
return (
<div>
<h3>Child Component</h3>
<input
type="text"
onChange={this.onMessageChange}
placeholder="Enter a message"
/>
<button onClick={this.onSubmit}>Submit</button>
</div>
);
}
}
Example:
<div {...this.props}>
Content Here
</div>
const person = {
name: "Alex",
age: 26,
coun : "India"
}
ReactDOM.render(
<SpreadExample {...person}/>
, mountNode
)
# 6. REACT STATE
Example:
/**
* React State
*/
export default class Employee extends React.Component {
constructor() {
super();
this.state = {
id: 100,
name: "Sarita Mangat"
};
}
render() {
return (
<div>
<div>ID: {this.state.id}</div>
<div>Name: {this.state.name}</div>
</div>
);
}
}
Always use the setState() method to change the state object, since it will ensure that the component knows it's been updated and
calls the render() method.
Example:
/**
* React setState()
*/
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
color: "blue"
};
}
handleColor = () => {
this.setState({ color: "red" });
};
render() {
return (
<div>
<h3 style={{ color: `${this.state.color}` }}>
Color: {this.state.color}
</h3>
this.setState(
{ username: 'Lila' },
() => console.log('setState has finished and the component has re-rendered.')
)
The setState() will always lead to a re-render unless shouldComponentUpdate() returns false. To avoid unnecessary renders, calling
setState() only when the new state differs from the previous state makes sense and can avoid calling setState() in an infinite loop
within certain lifecycle methods like componentDidUpdate().
↥
this.state = {
user: { name: 'Vasuda Handa', age: 22 }
}
Using Object.assign()
this.setState(prevState => {
let user = Object.assign({}, prevState.user); // creating copy of state variable user
user.name = 'Sai Gupta'; // update the name property, assign a new value
return { user }; // return new object user object
})
this.setState(prevState => ({
user: { // object that we want to update
...prevState.user, // keep all other key-value pairs
name: 'Niraj Gara' // update the value of specific key
}
}))
constructor(props) {
super(props)
this.state = {
fruits: ['apple', 'orange'],
count: 0
}
}
render() {
return (
<div className = "container">
<h2> Hello!!!</h2>
<p> I have {this.state.count} fruit(s)</p>
</div>
)
}
}
Example:
this.state = {
list: [
{ id: '1', age: 42 },
{ id: '2', age: 33 },
{ id: '3', age: 68 },
],
}
}
onRemoveItem = id => {
this.setState(state => {
const list = state.list.filter(item => item.id !== id)
return {
list,
}
})
}
render() {
return (
<div>
<ul>
{this.state.list.map(item => (
<li key={item.id}>
The person is {item.age} years old.
<button
type="button"
onClick={() => this.onRemoveItem(item.id)}
>
Remove
</button>
</li>
))}
</ul>
</div>
)
}
}
onDeleteByIndex(index) {
this.setState({
users: this.state.users.filter((item, i) => i !== index)
});
}
However, there may be cases where the render() method depends on some other data. After the initial mounting of components, a
re-render will occur.
Using forceUpdate():
The following example generates a random number whenever it loads. Upon clicking the button, the forceUpdate() function is called
which causes a new, random number to be rendered:
/**
* forceUpdate()
*/
export default class App extends React.Component {
constructor(){
super();
this.forceUpdateHandler = this.forceUpdateHandler.bind(this);
};
forceUpdateHandler(){
this.forceUpdate();
};
render(){
return(
<div>
<button onClick= {this.forceUpdateHandler} >FORCE UPDATE</button>
<h4>Random Number : { Math.random() }</h4>
</div>
);
}
}
Note: We should to avoid all uses of forceUpdate() and only read from this.props and this.state in render().
↥
Solution:
this.setState((prevState) => ({
count: prevState.count + 1
}));
this.setState((prevState) => ({
count: prevState.count + 1
}));
this.setState((prevState) => ({
count: prevState.count + 1
}));
// this.state.count === 3 as expected
Example:
// Nested object
state = {
name: 'Vyasa Agarwal',
address: {
colony: 'Old Cross Rds, Mehdipatnam',
city: 'Patna',
state: 'Jharkhand'
}
};
handleUpdate = () => {
// Overriding the city property of address object
this.setState({ address: { ...this.state.address, city: "Ranchi" } })
}
Props can be accessed by the child component. State cannot be accessed by child components.
Stateless component can have Props. Stateless components cannot have State.
In functional component, listen state changes with useEffect hook like this
useEffect(() => {
console.log(myState, '- Has changed')
},[myState]) // <-- here put the parameter to listen
}
In React we can access the child's state using React.createRef(). We will assign a Refs for the child component in the parent
component, then using Refs we can access the child's state.
// App.js
// Child.js
/**
* Change Child state from its Parent
* @param {*} param0
*/
const Child = ({ open }) => {
return <h2>Child State: {open.toString()}</h2>;
};
return (
<div>
<button onClick={toggleChild}>Click Me</button>
{/* Pass a callback to Child */}
<Child open={isOpen} />
</div>
);
};
checkAge = () => {
const { age } = this.state
if (age !== 0 && age >= 21) {
// Make API call to /beer
} else {
// Throw error 404, beer not found
}
}
render() {
const { age } = this.state
return (
<div>
<p>Drinking Age Checker</p>
<input
type="number"
value={age}
onChange={e => this.updateAge(e.target.value)}
/>
</div>
)
}
}
export default App
Example: setState Callback in a Functional Component
function App() {
const [age, setAge] = useState(0)
updateAge(value) {
setAge(value)
}
useEffect(() => {
if (age !== 0 && age >= 21) {
// Make API call to /beer
} else {
// Throw error 404, beer not found
}
}, [age])
return (
<div>
<p>Drinking Age Checker</p>
<input
type="number"
value={age}
onChange={e => setAge(e.target.value)}
/>
</div>
)
}
This is data maintained inside a component. It is local or owned by that specific component. The component itself will update the
state using the setState() function.
Example:
render() {
return <div>Message {this.state.msg}</div>
}
}
2. Props:
Data passed in from a parent component. props are read-only in the child component that receives them. However, callback
functions can also be passed, which can be executed inside the child to initiate an update.
Example: The parent can pass a props by using this
Props can be used to set the internal state based on a prop value in the constructor, like this
Props should never be changed in a child component. Props are also used to allow child components to access methods defined in
the parent component. This is a good way to centralize managing the state in the parent component, and avoid children to have the
need to have their own state.
Props State
Props can be accessed by the child component. State cannot be accessed by child components.
Stateless component can have Props. Stateless components cannot have State.
Props are external and controlled by whatever renders the The State is internal and controlled by the React
component. Component itself.
# 7. REACT EVENTS
Example:
/**
* Event Handling in React
*/
export default class Toggle extends React.Component {
constructor(props) {
super(props);
this.state = { isToggleOn: true };
}
handleClick() {
this.setState((state) => ({
isToggleOn: !state.isToggleOn
}));
}
render() {
return (
<button onClick={() => this.handleClick()}>
{this.state.isToggleOn ? "ON" : "OFF"}
</button>
);
}
}
render() {
return (
<button onClick={() => this.displayMessage(message)}>CLICK ME</button>
);
}
}
return (
<div>
<div>Counter: {counter}</div>
<CustomButton onCustomClick={handleCustomClick}/>
</div>
);
}
⚝
↥
<button onclick="handleClick()"></button>
In React, the attribute name is camelCase and are passed the function reference inside curly braces:
In HTML, false can be returned to prevent default behavior, whereas in React preventDefault() has to be called explicitly.
<a href="#" onclick="console.log('The link was clicked.'); return false" />
function handleClick(e) {
e.preventDefault()
console.log("The link was clicked.")
}
We can bind the handler when it is called in the render method using bind() method.
handleClick() {
// ...
}
<button onClick={this.handleClick.bind(this)}>Click</button>
In this approach we are binding the event handler implicitly. This approach is the best if you want to pass parameters to your event.
handleClick() {
// ...
}
This has performance benefits as the events aren't binding every time the method is called, as opposed to the previous two
approaches.
constructor(props) {
handleClick() {
// ...
}
<button onClick={this.handleClick}>Click</button>
the event handler method loses its implicitly bound context. When the event occurs and the handler is invoked, the this value falls
back to default binding and is set to undefined, as class declarations and prototype methods run in strict mode.
When we bind the this of the event handler to the component instance in the constructor, we can pass it as a callback without
worrying about it losing its context.
Arrow functions are exempt from this behavior because they use lexical this binding which automatically binds them to the scope
they are defined in.
Example:
/**
* Event Handling in React
*/
import React from "react";
handleClick(event) {
alert("Click event triggered!");
}
render() {
return <button onClick={this.handleClick}>Click Me</button>;
}
}
Example:
/**
* Pass parameter to an event handler
*/
const A = 65; // ASCII character code
handleClick(letter) {
this.setState({ justClicked: letter });
}
render() {
return (
<>
Just clicked: {this.state.justClicked}
<ul>
{this.state.letters.map((letter) => (
<li key={letter} onClick={() => this.handleClick(letter)}>
{letter}
</li>
))}
</ul>
</>
);
}
}
handleClick = () => {
this.setState({ backgroundColor: 'red' })
}
}
ReactDOM.render(
<Button />,
document.getElementById('root')
)
1. When we use this it generates a new function on every render, which will obviously have a new reference.
2. If the component we pass this generated function to is extending PureComponent(), it will not be able to bail out on
rerendering, even if the actual data has not changed.
deleteUser = id => {
this.setState(prevState => {
return {
users: prevState.users.filter(user => user.id !== id)
};
});
};
render() {
return (
<div>
<ul>
{this.state.users.map(user => {
return (
<User key={user.id} name={user.name} id={user.id}
onDeleteClick={() => this.deleteUser(user.id)}
/>
);
})}
</ul>
</div>
);
}
}
Solution:
In below example, App Component has no arrow function in render. Instead, the relevant data is passed down to User Component.
In User Component, onDeleteClick() calls the onClick function passed in on props with the relevant user.id.
// User Component
render() {
console.log(`${this.props.user.name} just rendered`);
return (
<li>
<input type="button" value="Delete" onClick={this.onDeleteClick} />
{this.props.user.name}
</li>
);
}
}
// App Component
deleteUser = id => {
this.setState(prevState => {
return {
users: prevState.users.filter(user => user.id !== id)
};
});
};
renderUser = user => {
return <User key={user.id} user={user} onClick={this.deleteUser} />;
}
render() {
return (
<div>
<ul>
{this.state.users.map(this.renderUser)}
</ul>
</div>
);
}
}
Usually when we want to access this inside a class method we would need to bind it to method like so:
Binding this to handleClick() in the constructor() allows us to use this.setState() from Component inside handleClick().
2. Bind in Render:
onChange={this.handleChange.bind(this)}
This approach is terse and clear, however, there are performance implications since the function is reallocated on every render.
3. Bind in Constructor:
constructor(props) {
super(props)
this.handleChange = this.handleChange.bind(this)
}
This is the approach currently recommended in the React docs for "better performance in your application".
2. Class Properties:
3. Bind in Render:
Note: Using Function.prototype.bind in render creates a new function each time the component renders, which may have performance
implications
4. Arrow Function in Render:
Note: Using an arrow function in render creates a new function each time the component renders, which may break optimizations
based on strict identity comparison.
Throttling prevents a function from being called more than once in a given window of time.
2. Debounce:
Debouncing ensures that a function will not be executed until after a certain amount of time has passed since it was last called. This
can be useful when you have to perform some expensive calculation in response to an event that might dispatch rapidly (eg scroll or
keyboard events).
Example:
/**
* Throttle and Debounce in React
*/
import * as React from "react";
import * as _ from "lodash";
render() {
return (
<div>
{this.state.count}
<hr />
<button onClick={this.handleThrottle}>Click Me - Throttle </button>
<button onClick={this.handleDebounce}>Click Me - Debounce </button>
</div>
);
}
}
3. RequestAnimationFrame Throttling:
The requestAnimationFrame is a way of queuing a function to be executed in the browser at the optimal time for rendering
performance. A function that is queued with requestAnimationFrame will fire in the next frame. The browser will work hard to ensure
that there are 60 frames per second (60 fps). However, if the browser is unable to it will naturally limit the amount of frames in a
second.
For example, a device might only be able to handle 30 fps and so you will only get 30 frames in that second. Using
requestAnimationFrame for throttling is a useful technique in that it prevents you from doing more than 60 updates in a second. If
you are doing 100 updates in a second this creates additional work for the browser that the user will not see anyway.
/**
* RequestAnimationFrame Throttling
*/
import rafSchedule from "raf-schd";
import React from "react";
this.handleScroll = this.handleScroll.bind(this);
handleScroll(e) {
// When we receive a scroll event, schedule an update.
// If we receive many updates within a frame, we'll only publish the latest value.
this.scheduleUpdate({ x: e.clientX, y: e.clientY });
}
componentWillUnmount() {
// Cancel any pending updates since we're unmounting.
this.scheduleUpdate.cancel();
}
render() {
return (
<div style={{ overflow: "scroll" }} onScroll={this.handleScroll}>
<img src="/my-huge-image.png" alt="Nature" />
</div>
);
}
}
⚝
↥
function handleClick(event) {
setTimeout(function () {
console.log(event.target.name)
}, 1000)
}
function handleClick(event) {
let name = event.target.name
setTimeout(function () {
console.log(name)
}, 1000)
}
SyntheticEvent Object
void preventDefault()
void stopPropagation()
boolean isPropagationStopped()
boolean isDefaultPrevented()
void persist()
boolean bubbles
boolean cancelable
DOMEventTarget currentTarget
boolean defaultPrevented
number eventPhase
boolean isTrusted
DOMEvent nativeEvent
DOMEventTarget target
number timeStamp
string type
function onClick(event) {
console.log(event) // => nullified object.
console.log(event.type) // => "click"
const eventType = event.type // => "click"
setTimeout(function() {
console.log(event.type) // => null
console.log(eventType) // => "click"
}, 0)
If we want to access the event properties in an asynchronous way, we should call event.persist() on the event, which will remove
the synthetic event from the pool and allow references to the event to be retained by user code.
↥
Q. How to trigger click event programmatically?
We can use ref prop to acquire a reference to the underlying HTMLInputElement object through a callback, store the reference as a
class property, then use that reference to later trigger a click from your event handlers using the HTMLElement.click method.
Example:
render() {
return (
<div onClick={this.handleClick}>
<input ref={input => this.inputElement = input} />
</div>
)
}
Note: The ES6 arrow function provides the correct lexical scope for this in the callback.
↥
componentWillUnmount() {
document.removeEventListener("mousedown", this.handleClickOutside);
}
/**
* Set the wrapper ref
*/
setWrapperRef(node) {
this.wrapperRef = node;
}
/**
* Alert if clicked on outside of element
*/
handleClickOutside(event) {
if (this.wrapperRef && !this.wrapperRef.contains(event.target)) {
alert("You clicked outside of me!");
}
}
render() {
return <div ref={this.setWrapperRef}>{this.props.children}</div>;
}
}
OutsideAlerter.propTypes = {
children: PropTypes.element.isRequired
};
↥
Q. How to convert text to uppercase on user input
entered?
import React, { useState } from "react"
import ReactDOM from "react-dom"
return (
<input
name={name}
onChange={e => setName(e.target.value)}
onInput={toInputUppercase} // apply on input which do you want to be capitalize
/>
)
}
onChange(e) {
const key = e.target.name
const value = e.target.value
this.setState({ [key]: value })
}
2. Nested States:
The API of pointer events works in the same manner as existing various event handlers. Pointer events are added as attributes to
React component and are passed a callback that accepts an event. Inside the callback we process the event.
onPointerDown
onPointerMove
onPointerUp
onPointerCancel
onGotPointerCapture
onLostPointerCapture
onPointerEnter
onPointerLeave
onPointerOver
onPointerOut
// App Component
import React, { Component } from 'react'
import logo from './logo.svg'
import './App.css'
import DragItem from './DragItem'
DragItem Component
state = {
gotCapture: false,
circleLeft: 500,
circleTop: 100
}
isDragging = false
previousLeft = 0
previousTop = 0
onDown = e => {
this.isDragging = true
e.target.setPointerCapture(e.pointerId)
this.getDelta(e)
}
onMove = e => {
if (!this.isDragging) {
return
}
return delta
}
render() {
const {gotCapture, circleLeft, circleTop} = this.state
const boxStyle = {
border: '2px solid #cccccc',
margin: '10px 0 20px',
minHeight: 400,
width: '100%',
position: 'relative',
}
const circleStyle = {
width: CIRCLE_DIAMETER,
height: CIRCLE_DIAMETER,
borderRadius: CIRCLE_DIAMETER / 2,
position: 'absolute',
left: circleLeft,
top: circleTop,
backgroundColor: gotCapture ? 'red' : 'green',
touchAction: 'none',
}
return (
<div style={boxStyle}>
<div
style={circleStyle}
onPointerDown={this.onDown}
onPointerMove={this.onMove}
onPointerUp={this.onUp}
onPointerCancel={this.onUp}
onGotPointerCapture={this.onGotCapture}
onLostPointerCapture={this.onLostCapture}
/>
</div>
)
}
}
Note: It work only in browsers that support the Pointer Events specification
constructor(props) {
super(props)
this.handleClick = this.handleClick.bind(this)
}
handleClick() {
console.log('Clicked !')
}
render() {
return <button onClick={this.handleClick}>Click Me</button>
}
}
2. Bind in Render:
handleClick() {
console.log('Clicked !')
}
render() {
return <button onClick={this.handleClick.bind(this)}>Click Me</button>
}
}
3. Arrow Function in Render:
handleClick() {
console.log('Clicked !')
}
render() {
return <button onClick={() => this.handleClick()}>Click Me</button>
}
}
Using an arrow function in render creates a new function each time the component renders, which may break optimizations based
on strict identity comparison.
Example:
# 8. REACT LISTS
Example:
/**
* React List
*/
export default class App extends Component {
state = {
lists: [
{ id: 0, context: "Success" },
{ id: 1, context: "Warning" },
{ id: 2, context: "Danger" }
]
};
render() {
return (
<>
<h2>React List</h2>
<ul className="list-group">
{this.state.lists.map((list) => (
<li key={list.id}>{list.context}</li>
))}
</ul>
</>
);
}
}
Example:
React recommends that you do not use indexes as keys, if the order of items may change. It could impact performance negatively
and could lead to some unstable component behaviour.
/**
* String Component
*/
const StringList = (props) => (
<div>
<h2>Render String List</h2>
{["test", "render", "array", "list"]}
</div>
);
/**
* Number Component
*/
const numbers = [10, 20, 30];
const NumberList = (props) => (
<div>
<h2>Render Number List</h2>
{numbers.map((item, index) => (
<div key={index}>{item}</div>
))}
</div>
);
Example:
/**
* API call using fetch()
*/
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
users: []
};
}
componentDidMount() {
fetch("https://api.github.com/users")
.then((res) => res.json())
.then((result) => {
this.setState({ users: result });
});
}
render() {
const { users } = this.state;
return (
<ul>
{users.map((user) => (
<li key={user.id}>
<img src={user.avatar_url} alt={user.login} width="100px" />
</li>
))}
</ul>
);
}
}
Example:
/**
* GET Request using Axios
*/
import React, { useEffect, useState } from "react";
import axios from "axios";
useEffect(() => {
fetchData();
}, []);
return (
<div>
{users.length > 0 && (
<ul>
{users.map((user) => (
<li key={user.id}>{user.name}</li>
))}
</ul>
)}
</div>
);
}
/**
* POST Request using Axios
*/
const user = {
name: this.state.name
};
axios
.post(`https://jsonplaceholder.typicode.com/users`, { user })
.then((res) => {
this.setState({ result: res.data.user.name });
});
};
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<label>
Person Name:
<input type="text" name="name" onChange={this.handleChange} />
</label>
<button type="submit">Add</button>
</form>
<h4>Result: {this.state.result}</h4>
</div>
);
}
}
The Fetch API provides a fetch() method defined on the window object. It also provides a JavaScript interface for accessing and
manipulating parts of the HTTP pipeline (requests and responses). The fetch method has one mandatory argument- the URL of the
resource to be fetched. This method returns a Promise that can be used to retrieve the response of the request.
Example:
fetch('path-to-the-resource-to-be-fetched')
.then((response) => {
// Code for handling the response
})
.catch((error) => {
// Error Handling
});
2. Axios():
Axios is a Javascript library used to make HTTP requests from node.js or XMLHttpRequests from the browser and it supports the
Promise API that is native to JS ES6. It can be used intercept HTTP requests and responses and enables client-side protection against
XSRF. It also has the ability to cancel requests.
Example:
axios.get('url')
.then((response) => {
// Code for handling the response
})
.catch((error) => {
// Error Handling
});
Differences:
Axios() Fetch()
Axios has url in request object. Fetch has no url in request object.
Axios uses the data property. Fetch uses the body property.
Axios performs automatic transforms of Fetch is a two-step process when handling JSON data- first, to make the actual
JSON data. request; second, to call the .json() method on the response.
Interceptors are methods which are triggered before or after the main method. There are two types of interceptors:
1. Request Interceptor:
This is called before the actual call to the endpoint is made. One common use case for a request handler is to modify or add new
HTTP headers. For example, an authentication token could be injected into all requests.
Example:
// Request Handler
const requestHandler = (request) => {
const token = localStorageService.getAccessToken()
if (token) {
request.headers['Authorization'] = 'Bearer ' + token
}
return request
}
// Request Interceptor
axios.interceptors.request.use(
request => requestHandler(request)
)
This is called before the promise is completed and the data is received by the then callback.
Example:
// Response Handlers
const errorHandler = (error) => {
if (isHandlerEnabled(error.config)) {
// Handle errors
}
return Promise.reject({ ...error })
}
// Response Interceptors
axios.interceptors.response.use(
response => successHandler(response),
error => errorHandler(error)
)
Local Storage
Redux Store
Keep data between mouting and unmounting
useMemo()
Memoization is a technique we would use to make sure that we don't hit the API if we have made some kind of request to fetch it at
some initial phase. Storing the result of expensive fetch calls will save the users some load time, therefore, increasing overall
performance.
Example:
const cache = {}
useEffect(() => {
if (!url) return
if (cache[url]) {
const data = cache[url]
setData(data)
setStatus('fetched')
} else {
const response = await fetch(url)
const data = await response.json()
cache[url] = data // set response in cache
setData(data)
setStatus('fetched')
}
}
fetchData()
}, [url])
return { status, data }
}
Here, we're mapping URLs to their data. So, if we make a request to fetch some existing data, we set the data from our local cache,
else, we go ahead to make the request and set the result in the cache. This ensures we do not make an API call when we have the
data available to us locally.
With useRef(), we can set and retrieve mutable values at ease and its value persists throughout the component's lifecycle.
const useFetch = (url) => {
const cache = useRef({})
const [status, setStatus] = useState('idle')
const [data, setData] = useState([])
useEffect(() => {
if (!url) return
if (cache.current[url]) {
const data = cache.current[url]
setData(data)
setStatus('fetched')
} else {
const response = await fetch(url)
const data = await response.json()
cache.current[url] = data // set response in cache
setData(data)
setStatus('fetched')
}
}
fetchData()
}, [url])
3. Using localStorage():
const InitialState = {
someState: 'a'
}
class App extends Component {
constructor(props) {
super(props)
componentWillUnmount() {
// Remember state for the next mount
localStorage.setItem('appState', JSON.stringify(this.state))
}
render() {
...
}
}
constructor(props) {
super(props)
this.onClick = this.onClick.bind(this)
}
componentWillUnmount() {
// Remember state for the next mount
state = this.state
}
onClick(e) {
e.preventDefault()
this.setState(prev => ({ counter: prev.counter + 1 }))
}
render() {
return (
<div>
<span>{ this.state.counter }</span>
<button onClick={this.onClick}>Increase</button>
</div>
)
}
}
/**
* API call in componentDidMount()
*/
import React from "react";
componentDidMount() {
fetch("https://dummy.restapiexample.com/api/v1/employees")
.then((res) => res.json())
.then((result) => {
this.setState({
isLoaded: true,
users: result.data
});
})
.catch((error) => {
this.setState({
isLoaded: false,
error
});
});
}
render() {
const { error, isLoaded, users } = this.state;
if (error) {
return <div>Error: {error.message}</div>;
} else if (!isLoaded) {
return <div>Loading...</div>;
} else {
return (
<ul>
{users.length > 0 &&
users.map((user) => <li key={user.id}>{user.employee_name}</li>)}
</ul>
);
}
}
}
if (!response.ok) {
throw Error(response.statusText);
} else {
const json = await response.json();
this.setState({ data: json });
}
} catch (error) {
console.log(error);
}
}
render() {
return (
<div>
<ul>
{this.state.data.map((el) => (
<li key={el.id}>
<img src={el.avatar_url} alt={el.avatar_url} />
<span className="UserLogin">{el.login}</span>
</li>
))}
</ul>
</div>
);
}
}
RxJS Terminology
Observable: An Observable is a data stream that houses data that can be passed through different threads.
Observer: An Observer consumes the data supplied by an Observable
Subscription: In order for Observer to consume data from Observable, Observer has to subscribe it to the Observable.
Subject: An RxJS Subject can act as both an Observable and an Observer at the same time. In this way, values can be
multicasted to many Observers from it so that when a Subject receives any data, that data can be forwarded to every
Observer subscribed to it.
Operators: Operators are methods that can use on Observables and subjects to manipulate, filter or change the
Observable in a specified manner into a new Observable.
BehaviorSubject: It allows multiple observers to listen on stream and events multicasted to the observers,
BehaviorSubject stores the latest value and broadcasts it to any new subscribers.
Example:
// messageService.js
import { BehaviourSubject } from 'rxjs'
const messageService = {
send: function(msg) {
subscriber.next(msg)
}
}
export {
messageService,
subscriber
}
The messageService object has a send function, which takes a msg parameter which holds the data we need to broadcast all
listening components, in the function body we call the emit method in the subscriber object it multicasts the data to the subscribing
components.
componentDidMount() {
subscriber.subscribe((v) => {
let { counter } = this.state
counter = counter + v
this.setState({ counter })
})
}
render() {
let { counter } = this.state
return (
<div>
<hr/>
<h3> Counter for Consumer A </h3>
<div> Counter: {counter} </div>
<hr/>
</div>
)
}
}
render() {
let { counter } = this.state
return (
<div>
<hr/>
<h3>Counter for Consumer B</h3>
<div> Counter: { counter } </div>
<hr/>
<ProducerB />
</div>
)
}
}
render(<App/>, document.getElementById('root'));
The ConsumerA and ConsumerB components keep a state counter individual. In their componentDidMount they subscribe to the
same stream subscriber, anytime an event is published they both update the counter. The ProducerA and ProducerB have buttons
Increment Counter and Decrement Counter when clicked they emit 1 or -1.
Reference:
https://www.learnrxjs.io/
constructor(props) {
super(props);
this.state = {
colors: {}
};
this.selectColor = this.selectColor.bind(this);
}
componentDidMount() {
this.setState({
colors: {
"#ff0000": "Red",
"#00ff00": "Green",
"#0000ff": "Blue"
}
});
}
render() {
const { colors } = this.state;
return (
<div>
<select onChange={this.selectColor}>{colorsList}</select>
</div>
);
}
}
return (
<form onSubmit={handleSubmit}>
<h1>Create Account</h1>
<label>Email:
<input name="email" type="email" value={email}
onChange={(e) => setEmail(e.target.value)}
required
/>
</label>
<label>Password:
<input name="password" type="password" value={password}
onChange={(e) => setPassword(e.target.value)}
required
/>
</label>
<label>Coun :
<select name="coun " value={coun }
onChange={(e) => setCoun (e.target.value)}
required
>
<option key=""></option>
{countries.map((coun ) => (
<option key={coun }>{coun }</option>
))}
</select>
</label>
<button>Submit</button>
</form>
);
}
Output:
⚝
Example:
"& .MuiTextField-root": {
margin: theme.spacing(1),
width: "300px"
},
"& .MuiButtonBase-root": {
margin: theme.spacing(2)
}
}
}));
return (
<form className={classes.root} onSubmit={handleSubmit(onSubmit)}>
<Controller
name="email"
control={control}
defaultValue=""
render={({ field: { onChange, value }, fieldState: { error } }) => (
<TextField
label="Email"
variant="filled"
value={value}
onChange={onChange}
error={!!error}
helperText={error ? error.message : null}
type="email"
/>
)}
rules={{ required: "Email required" }}
/>
<Controller
name="password"
control={control}
defaultValue=""
render={({ field: { onChange, value }, fieldState: { error } }) => (
<TextField
label="Password"
variant="filled"
value={value}
onChange={onChange}
error={!!error}
helperText={error ? error.message : null}
type="password"
/>
)}
rules={{ required: "Password required" }}
/>
<div>
<Button variant="contained" onClick={handleClose}>
Cancel
</Button>
<Button type="submit" variant="contained" color="primary">
Signup
</Button>
</div>
</form>
);
};
React Hook Form isolates the component and avoids the other components from re-rending. This feature will improve the
performance by avoiding unwanted rendering in other child components. However, libraries like Formik and Redux-Form re-render
the other child components along with the form component.
2. Reduce Rendering:
Besides isolating the component, it also limits its own (form components) form re-rendering on particular events such as onChange,
onBlur, etc.
3. Faster Mounting:
Mounting time is about 13% faster than Formik and 25% faster than Redux-Form. In other words, the form's DOM elements will be
inserted into the DOM tree quicker, leading to fast rendering compared with other libraries.
React Hook Form allows you to subscribe to each input element without going through the re-rendering of each element inside the
form component.
5. Typescript Support:
React Hook Form is built with TypeScript and can define a FormData type to support form values.
The React Hook Form provides a hook called useForm(), consisting of methods and props handleSubmit, register, and errors. They
would handle the submit events, the input via refs using register, and display any errors. However, in the other two libraries, you
need to write your custom handlers for events and validations.
↥
1. Controlled Components:
In a controlled component, the form data is handled by the state within the component. The state within the component serves as
“the single source of truth” for the input elements that are rendered by the component.
Example:
/**
* Controlled Components
*/
import React, { Component } from "react";
2. Uncontrolled Components:
Uncontrolled components act more like traditional HTML form elements. The data for each input element is stored in the DOM, not
in the component. Instead of writing an event handler for all of your state updates, It uses ref to retrieve values from the
DOM. Refs provide a way to access DOM nodes or React elements created in the render method.
/**
* Uncontrolled Component
*/
import React, { Component } from "react";
↥
Q. How do you set default value for uncontrolled
components?
React provides defaultValue attribute that pre-populate the input field with the default Value without overriding any value input by
the user.
Example:
/**
* React defaultValue
*/
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input
defaultValue="Samir Chahal"
type="text"
ref={this.input} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
Rules of Hooks:
Built-in Hooks:
Hooks Description
useState() To manage states. Returns a stateful value and an updater function to update it.
useEffect() To manage side-effects like API calls, subscriptions, timers, mutations, and more.
useCallback() It returns a memorized version of a callback to help a child component not re-render unnecessarily.
useRef() It returns a ref object with a .current property. The ref object is mutable. It is mainly used to access a child
component imperatively.
useImperativeHandle() It customizes the instance value that is exposed to parent components when using ref.
It fires at the end of all DOM mutations. It's best to use useEffect as much as possible over this one as the
useLayoutEffect()
useLayoutEffect fires synchronously.
/**
* useState() Hooks
*/
import React, { useState } from "react";
return (
<button onClick={() => setIsButtonClickedStatus(!isButtonClicked)}>
{isButtonClicked ? "Clicked" : "Click Me, Please"}
</button>
);
}
/**
* Custom Hook
*/
import { useState, useEffect } from "react";
useEffect(() => {
fetch(url)
.then((res) => res.json())
.then((data) => setData(data));
}, [url]);
return [data];
};
/**
* App Component
*/
import "./styles.css";
import useFetch from "./useFetch";
Example:
/**
* useState() and useEffect() Hooks
*/
import React, { useState, useEffect } from "react";
useEffect(() => {
fetch("https://api.github.com/users")
.then((response) => response.json())
.then((data) => {
setUsers(data);
});
}, []);
return (
<div>
{users.map((user) => (
<div key={user.id}>
<span>
<img src={user.avatar_url} width={"30px"} alt={user.avatar_url} />
</span>
<span> {user.login.toUpperCase()}</span>
</div>
))}
</div>
);
}
Hooks were designed to replace class and provide another great alternative to compose behavior into your components. Higher
Order Components are also useful for composing behavior. Hooks encapsulate the functionality to easily reusable functions
const [active, setActive] = useState(defaultActive)
import {
useState,
useReducer,
useEffect,
useCallback,
useMemo,
useRef,
...
} from 'react'
A Higher Order Component (HOC) is a component that takes a component and returns a component. HOCs are composable using
point-free, declarative function composition.
To use it, you can mix it into an HOC that you\’ll wrap around every page:
Example:
useEffect(() => {
console.log("prevCount: ", prevCount, "count: ", count);
}, [prevCount, count]);
return (
<div>
<button onClick={() => setCount((c) => c + 10)}>Increment</button>
<p>{count}</p>
</div>
);
}
Here, We create the usePrevious hook with the value parameter which is state we want to get the previous value from, In the hook,
we create a ref with the useRef hook to create a non-reactive property. Then we add the useEffect hook with a callback that sets
the ref.current to value to set the previous value.
function useWindowSize() {
useLayoutEffect(() => {
function updateSize() {
setSize([window.innerWidth, window.innerHeight])
}
window.addEventListener('resize', updateSize)
updateSize()
return () => window.removeEventListener('resize', updateSize)
}, [])
return size
}
function ShowWindowDimensions(props) {
updateDimensions = () => {
this.setState({ width: window.innerWidth, height: window.innerHeight })
}
/**
* Add event listener
*/
componentDidMount() {
window.addEventListener('resize', this.updateDimensions)
}
/**
* Remove event listener
*/
componentWillUnmount() {
window.removeEventListener('resize', this.updateDimensions)
}
render() {
return (
<span>Window size: {this.state.width} x {this.state.height}</span>
)
}
}
The example below is equivalent to forceUpdate() method in class-based components. This hook works in the following way:
The useState() hook returns an array with two elements, a value and an updater function.
Here, we are instantly calling the updater function, which in this case is called with undefined, so it is the same as
calling updater(undefined).
Example:
/**
* Rerender Component with useState()
*/
import React, { useState } from "react";
⚝
↥
return (
<div>
Count: {count}
<hr />
<div>
<button type="button" onClick={handleIncrease}>
Increase
</button>
<button type="button" onClick={handleDecrease}>
Decrease
</button>
</div>
</div>
)
}
The useState() function takes as argument a value for the initial state. In this case, the count starts out with 0. In addition, the hook
returns an array of two values: count and setCount. It's up to you to name the two values, because they are destructured from the
returned array where renaming is allowed.
↥
const initialState = 0
const reducer = (state, action) => {
switch (action) {
case 'increment': return state + 1
case 'decrement': return state - 1
case 'reset': return 0
default: throw new Error('Unexpected action')
}
}
Here, we first define an initialState and a reducer. When a user clicks a button, it will dispatch an action which updates the count and
the updated count will be displayed. We could define as many actions as possible in the reducer, but the limitation of this pattern is
that actions are finite.
this.state = {
searchString: ''
}
}
}
we are passing an empty string as a value and, to update the state of searchString, we have to call setState().
Here, we are passing an object to setState(). The object contains the part of the state we want to update which, in this case, is the
value of searchString. This is basically kicking off a process that React calls reconciliation. The reconciliation process is the way React
updates the DOM, by making changes to the component based on the change in state.
When the request to setState() is triggered, React creates a new tree containing the reactive elements in the component (along
with the updated state). This tree is used to figure out how the Search component's UI should change in response to the state
change by comparing it with the elements of the previous tree.
↥
Webhooks are also sometimes referred to as "Reverse APIs". In APIs, the client-side application calls (consumes) the server-side
application. Whereas, in case of web hooks it is the server-side that calls (consumes) the web hook (the end-point URL provided by
the client-side application), i.e. it is the server-side application that calls the client-side application.
React's useCallback() Hook can be used to optimize the rendering behavior of your React function components.
The useCallback will return a memoized version of the callback that only changes if one of the dependencies has changed.
This is useful when passing callbacks to optimized child components that rely on reference equality to prevent unnecessary renders
(e.g. shouldComponentUpdate).
Example:
/**
* useCallback()
*/
import React, { useState, useCallback, useEffect } from "react";
useEffect(() => {
count.add(increment);
console.log(count.size);
}, [increment]);
return (
<>
<h1>useCallback()</h1>
<h2>Function Call: {count.size}</h2>
<button onClick={increment}>Increment</button>
</>
);
}
2. useMemo()
The useMemo() is similar to useCallback() except it allows you to apply memoization to any value type. It does this by accepting a
function which returns the value and then that function is only called when the value needs to be retrieved.
Example:
React application which renders a list of users and allows us to filter the users by their name. The filter happens only when a user
explicitly clicks a button; not already when the user types into the input field.
const users = [
{ id: 'a', name: 'Robin' },
{ id: 'b', name: 'Dennis' },
]
// useMemo Hooks
const filteredUsers = React.useMemo(
() =>
users.filter((user) => {
console.log('Filter function is running ...');
return user.name.toLowerCase().includes(search.toLowerCase());
}),
[search]
);
return (
<div>
<input type="text" value={text} onChange={handleText} />
<button type="button" onClick={handleSearch}>
Search
</button>
Here, the filteredUsers function is only executed once the search state changes. It doesn't run if the text state changes, because
that's not a dependency for this filter function and thus not a dependency in the dependency array for the useMemo hook.
3. useImperativeHandle()
useImperativeHandle() customizes the instance value that is exposed to parent components when using ref. As always, imperative
code using refs should be avoided in most cases. useImperativeHandle should be used with forwardRef.
function FancyInput(props, ref) {
const inputRef = useRef()
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus()
}
}))
return <input ref={inputRef} ... />
}
FancyInput = forwardRef(FancyInput)
4. useLayoutEffect()
This runs synchronously immediately after React has performed all DOM mutations. This can be useful if you need to make DOM
measurements (like getting the scroll position or other styles for an element) and then make DOM mutations or trigger a
synchronous re-render by updating state.
As far as scheduling, this works the same way as componentDidMount and componentDidUpdate. Your code runs immediately after the
DOM has been updated, but before the browser has had a chance to "paint" those changes (the user doesn't actually see the
updates until after the browser has repainted).
Example:
useLayoutEffect(() => {
if (value === 0) {
setValue(10 + Math.random() * 200)
}
}, [value])
console.log('render', value)
return (
<div onClick={() => setValue(0)}>
value: {value}
</div>
)
}
useLayoutEffect vs useEffect
useLayoutEffect: If you need to mutate the DOM and/or do need to perform measurements
useEffect: If you don't need to interact with the DOM at all or your DOM changes are unobservable (seriously, most of the
time you should use this).
5. useDebugValue()
useDebugValue() can be used to display a label for custom hooks in React DevTools.
Example:
function useFriendStatus(friendID) {
const [isOnline, setIsOnline] = useState(null)
// ...
return isOnline
}
// Memo.js
// App.js
/**
* Counter Component
*/
const { useState, useContext } = React;
function Counter() {
const { count, increase, decrease } = useContext(CountContext);
return (
<h2>
<button onClick={decrease}>Decrement</button>
<span className="count">{count}</span>
<button onClick={increase}>Increment</button>
</h2>
);
}
/**
* App Component
*/
export default function App() {
const [count, setCount] = useState(0);
return (
<div>
<CountContext.Provider value={{ count, increase, decrease }}>
<Counter />
</CountContext.Provider>
</div>
);
}
Context API uses Context. Provider and Context. Consumer Components pass down the data but it is very cumbersome to write the
long functional code to use this Context API. So useContext hook helps to make the code more readable, less verbose and removes
the need to introduce Consumer Component. The useContext hook is the new addition in React 16.8.
Syntax:
The useContext accepts the value provided by React.createContext and then re-render the component whenever its value changes
but you can still optimize its performance by using memorization.
/**
* Default value in Context API
*/
import { createContext, useContext } from "react";
/**
* Child1 Component
*/
function Child1() {
const context = useContext(Context);
return <h2>Child1: {context}</h2>;
}
/**
* Child2 Component
*/
function Child2() {
const context = useContext(Context);
return <h2>Child2: {context}</h2>;
}
/**
* App Component
*/
export default function App() {
return (
<>
<Context.Provider value={"Initial Value"}>
<Child1 /> {/* Child inside Provider will get "Initial Value" */}
</Context.Provider>
<Child2 /> {/* Child outside Provider will get "Default Value" */}
</>
);
}
/**
* ContextType()
*/
import React, { Component } from "react";
import ReactDOM from "react-dom";
/**
* StoreProvider Component
*/
class StoreProvider extends Component {
state = {
count: 0
};
incrementCount = () => {
console.log("Increment");
const { count } = this.state;
this.setState({ count: count + 1 });
};
render() {
return (
<Provider
value={{
state: this.state,
incrementCount: this.incrementCount
}}
>
{this.props.children}
</Provider>
);
}
}
/**
* VoteCount Component
*/
class VoteCount extends Component {
static contextType = MyContext;
render() {
const { state, incrementCount } = this.context;
return (
<div>
<button onClick={incrementCount}>Click Me</button> {state.count}
</div>
);
}
}
Example:
/**
* React Context API
*/
import React, { useState, useContext } from "react";
const MyContext = React.createContext();
/**
* Child Component
*/
const MyComponent = () => {
const { count, increment } = useContext(MyContext);
return (
<div>
<button onClick={increment}>Click Me</button> {count}
</div>
);
};
/**
* App Component
*/
export default function App() {
const [count, updateCount] = useState(0);
function increment() {
updateCount(count + 1);
}
return (
<MyContext.Provider value={{ count, increment }}>
<div>
<MyComponent />
</div>
</MyContext.Provider>
);
}
Here, We are storing data in component state in which we want to use context and we created a function that modify this state. We
pass the state and function as context values. It then become possible from the child to get the function and to use it to update your
context.
⚝
The Context API solves some of these prop drilling problems. It let pass data to all of the components in the tree without writing
them manually in each of them. Shared data can be anything: state, functions, objects, we name it, and it is accessible to all nested
levels that are in the scope of the context.
Example:
/**
* Prop Drilling
*/
import React, { useContext, createContext } from "react";
function Display() {
const value = useContext(NumberContext);
return <h3>Contex Value: {value}</h3>;
}
/**
* React Router v6
*/
import { BrowserRouter, Route, Routes, NavLink } from "react-router-dom";
/**
* Home Component
*/
const Home = () => {
return <h1>Home Page</h1>;
};
/**
* Contacts Component
*/
const Contacts = () => {
return <h1>Contact Page</h1>;
};
/**
* App Component
*/
export default function App() {
return (
<div className="App">
<BrowserRouter>
<div className="navbar">
<NavLink to={"/"}>Home</NavLink>
<NavLink to={"/contact"}>Contact Us</NavLink>
</div>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/contact" element={<Contacts />} />
</Routes>
</BrowserRouter>
</div>
);
}
1. BrowserRouter:
BrowserRouter is a router implementation that uses the HTML5 history API (pushState, replaceState and the popstate event) to keep
your UI in sync with the URL. It is the parent component that is used to store all of the other components.
2. Routes:
It's a new component introduced in the v6 and a upgrade of the component. The main advantages of Routes over Switch that routes
are chosen based on the best match instead of being traversed in order.
3. Route:
Route is the conditionally shown component that renders some UI when its path matches the current URL.
4. Link:
Link component is used to create links to different routes and implement navigation around the application. It works like HTML
anchor tag.
<Link to="/">Home</Link>
NavLink
<NavLink to="/" activeClassName="active">Home</NavLink>
Example:
index.css
.active {
color: blue;
}
Routes.js
const Routes = (
<Router>
<div>
<ul>
<li>
<NavLink exact activeClassName="active" to="/">
Home
</NavLink>
</li>
<li>
<NavLink activeClassName="active" to="/users">
Users
</NavLink>
</li>
<li>
<NavLink activeClassName="active" to="/contact">
Contact
</NavLink>
</li>
</ul>
<hr />
<Switch>
<Route exact path="/" component={App} />
<Route path="/users" component={Users} />
<Route path="/contact" component={Contact} />
<Route component={Notfound} />
</Switch>
</div>
</Router>
)
ReactDOM.render(Routes, document.getElementById('root'))
render() {
const { match, location, history } = this.props
BrowserRouter
HashRouter
// <BrowserRouter>
http://example.com/about
// <HashRouter>
http://example.com/#/about
The <BrowserRouter> is the more popular of the two because it uses the HTML5 History API to keep your UI in sync with the URL,
whereas the <HashRouter> uses the hash portion of the URL (window.location.hash). If you need to support legacy browsers that
don't support the History API, you should use <HashRouter>. Otherwise <BrowserRouter> is the better choice for most use cases.
Example:
// src/index.js
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById("root")
);
The above code creates a history instance for our entire <App> component. Each <Router> component creates a history object that
keeps track of the current location (history.location) and also the previous locations in a stack. The history object has methods
such as history.push, history.replace, history.goBack, history.goForward etc.
↥
function Home() {
return <h1>Home Page</h1>;
}
function Users() {
return (
<ul>
<li><Link to={"/users/1"}>User 1</Link></li>
</ul>
);
}
function UserDetail() {
let { id } = useParams();
let navigate = useNavigate();
function handleClick() {
navigate("/users");
}
return (
<>
<h1>User Details Page: {id}</h1>
<button onClick={handleClick}>Back</button>
</>
);
}
function AppRoutes() {
return (
<Routes>
<Route path="/" element={<Home />} />
<Route path="users" element={<Users />} />
<Route path="users/:id" element={<UserDetail />} />
</Routes>
);
}
Example:
// http://localhost:3000/?id=100&name=react
const id = queryParams.get('id');
const name = queryParams.get('name');
/**
* React Router
*/
import { BrowserRouter, Routes, NavLink, Route, useParams, useNavigate } from "react-router-dom";
function Home() {
return <h2>Welcome Home</h2>;
}
function User() {
let { name, email } = useParams();
return (
<h2>Name: {name} <br /> Email: {email}</h2>
);
}
function HomeButton() {
const history = useNavigate();
function handleClick() {
history("/");
}
return (
<>
<button type="button" onClick={handleClick}>Go Home</button>
</>
);
}
Example:
/**
* Automatic Redirect in router-v6
*/
import { NavLink, BrowserRouter, Routes, Route, Navigate } from "react-router-dom";
Note: To keep the history clean, you should set replace prop. This will avoid extra redirects after the user click back.
⚝
Example:
/**
* Pass additional data while redirecting
*/
import { BrowserRouter, Link, Route, Routes, useLocation } from "react-router-dom";
/**
* View User Component
*/
function ViewUser() {
const location = useLocation();
return (
<>
<h2>User Details</h2>
<div>Name:{location.state.name}</div>
<div>Email:{location.state.email}</div>
</>
);
}
/**
* User Component
*/
function User() {
return (
<div>
<h2>Pass additional data while redirecting</h2>
<Link
to="/view-user"
state={{
name: "Kalini Khalsa",
email: "[email protected]"
}}
>
<button>View User</button>
</Link>
</div>
);
}
/**
* App Component
*/
export default function App() {
return (
<BrowserRouter>
<Routes>
<Route exact path="/" element={<User />} />
<Route exact path="/user" element={<User />} />
<Route exact path="/view-user" element={<ViewUser />} />
</Routes>
</BrowserRouter>
);
}
/**
* Pass props in React Router-v6
*/
import React from "react";
import { BrowserRouter, Routes, Route, NavLink } from "react-router-dom";
/**
* useParams()
*/
import React from "react";
import { BrowserRouter, Route, Routes, Link, useParams } from "react-router-dom";
function Child() {
// `useParams` hook used here to access parameters
let { id } = useParams();
The widely popular router and a router for modern browsers which user HTML5 pushState API.
(i.e. pushState, replaceState and popState API).
It routes as normal URL in browser, you can't differentiate whether it is server rendered page or client rendered page
through the URL.
It assumes, your server handles all the request URL (eg., /, /about) and points to root index.html. From there,
BrowserRouter take care of routing the relevant page.
It accepts forceRefresh props to support legacy browsers which doesn't support HTML5 pushState API
Syntax:
/**
* https://example.com/home
* https://example.com/about
*/
<BrowserRouter
basename={optionalString}
forceRefresh={optionalBool}
getUserConfirmation={optionalFunc}
keyLength={optionalNumber}
>
<App />
</BrowserRouter>
Example:
/**
* BrowserRouter()
*/
import { Link, BrowserRouter, Routes, Route } from "react-router-dom";
2. HashRouter:
Syntax:
/**
* https://example.com/#/home
* https://example.com/#/about
*/
<HashRouter
basename={optionalString}
getUserConfirmation={optionalFunc}
hashType={optionalString}
>
<App />
</HashRouter>
Example:
/**
* HashRouter()
*/
import { Link, HashRouter, Routes, Route } from "react-router-dom";
↥
Q. What is route based code splitting?
Route based code splitting is essential during the page transitions on the web, which takes some amount of time to load. Here is an
example of how to setup route-based code splitting into the app using React Router with React.lazy.
Example:
/**
* Lazy Loading
*/
import React, { Suspense, lazy } from "react";
import { BrowserRouter, Routes, Route } from "react-router-dom";
Q. What is code-splitting?
Code-Splitting is a feature supported by bundlers like Webpack, Rollup and Browserify ( via factor-bundle ) which can create
multiple bundles that can be dynamically loaded at runtime.
Code splitting uses React.lazy and Suspense library, which helps to load a dependency lazily and only load it when needed by the
user. The code splitting improves:
The React.lazy function allows us to render a dynamic import as a regular component. The suspense component is responsible for
handling the output when the lazy component is fetched and rendered.
Example:
function MyComponent() {
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<UsersComponent />
</Suspense>
</div>
);
}
Example:
function MyComponent() {
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<UsersComponent />
</Suspense>
</div>
);
}
Example:
function MyComponent() {
return (
<div>
<UsersComponent />
</div>
)
}
↥
Use static getDerivedStateFromError() to render a fallback UI after an error has been thrown. Use componentDidCatch() to log
error information.
Syntax:
<ErrorBoundary>
<User/>
</ErrorBoundary>
Example:
/**
* ErrorBoundary Component
*/
import React, {Component} from 'react'
Here, We have a state object having two variables isErrorOccured and errorMessage which will be updated to true if any error occurs.
⚝
{
// Some Calculation
} catch (error) {
console.log(`Error: ${error}`);
}
2. Error Boundaries deal with declarative code. Imperative programming is how you do something and declarative programming is
what you do.
With error boundary, if there is an error, you can trigger a fallback UI; whereas, with …catch, you can catch errors in your code.
import ErrorBoundary from "error-boundary";
function Users() {
return (
<div>
<ErrorBoundary>
<Users />
</ErrorBoundary>
</div>
)
}
Example:
A static method called getDerivedStateFromError(), which is used to update the error boundary's state
A componentDidCatch() lifecycle method for performing operations when our error boundaries catch an error, such as
logging to an error logging service
A render() method for rendering our error boundary's child or the fallback UI in case of an error
Example:
/**
* Error Boundary in React
*/
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error) {
// Update state so the next render will show the fallback UI.
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
// You can also log the error to an error reporting service
logErrorToMyService(error, errorInfo);
}
render() {
if (this.state.hasError) {
// You can render any custom fallback UI
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
Example:
/**
* Refs
*/
class App extends React.Component {
constructor(props) {
super(props)
// create a ref to store the textInput DOM element
this.textInput = React.createRef()
this.state = {
value: ''
}
}
render() {
return (
<div>
<h1>React Ref - createRef</h1>
{/** This is what will update **/}
<h3>Value: {this.state.value}</h3>
<form onSubmit={this.handleSubmit}>
{/** Call the ref on <input> so we can use it to update the <h3> value **/}
<input type="text" ref={this.textInput} />
<button>Submit</button>
</form>
</div>
)
}
}
Should not be used with functional components because they dont have instances.
Not to be used on things that can be done declaritvely.
/**
* Multiple Refs
*/
import React, { useRef } from "react";
return (
<div>
{arr.map((item, index) => {
return (
<div
key={index}
ref={(element) => {
refs.current[index] = element;
}}
>
{item}
</div>
);
})}
</div>
);
}
Example:
/**
* useRef()
*/
export default function App() {
const [count, setCount] = useState(0);
const ref = useRef();
useEffect(() => {
ref.current = "SomeInitialValue";
}, []);
useEffect(() => {
console.log(count, ref.current);
}, [count]);
return (
<div className="App">
<button onClick={() => setCount((c) => c + 1)}>Increment</button>
<p>{count}</p>
</div>
);
}
2. createRef():
The createRef is a function that creates a new ref every time. Unlike the useRef, it does not save its value between re-renders, instead
creates a new instance of the ref for every re-render. Thus implying that it does not persist the existing ref between re-renders.
Example:
/**
* createRef()
*/
export default function App() {
const [count, setCount] = useState(0);
const ref = createRef();
useEffect(() => {
ref.current = "SomeInitialValue";
}, []);
useEffect(() => {
console.log(count, ref.current);
}, [count]);
return (
<div className="App">
<button onClick={() => setCount((c) => c + 1)}>Increment</button>
<p>{count}</p>
</div>
);
}
/**
* Inline Ref Callback()
*/
import React from "react";
Here, When the <input> element is rendered, React calls the function defined in the ref attribute, passing that function
the <input> element as an argument.
⚝
render() {
return <div />
}
}
render() {
return <div ref={node => this.node = node} />
}
}
constructor(props) {
super(props)
this.textInput = React.createRef()
}
componentDidMount() {
this.textInput.current.focus()
}
render() {
return <input ref={this.textInput} />
}
}
Callback Refs:
Instead of passing a ref attribute created by createRef(), you pass a function. The function receives the React component instance
or HTML DOM element as its argument, which can be stored and accessed elsewhere.
Example:
// Ref.js
render() {
return (
<div>
<form onSubmit={(e) => this.handleSubmit(e)}>
<input type="text" ref={this.setTextInputRef} />
<button>Submit</button>
</form>
</div>
);
}
}
// App.js
// Ref.js
const TextInput = React.forwardRef((props, ref) => (
<input type="text" placeholder="Hello World" ref={ref} />
))
render() {
return (
<div>
<form onSubmit={e => this.handleSubmit(e)}>
<TextInput ref={inputRef} />
<button>Submit</button>
</form>
</div>
)
}
}
In the example above, we have a component called TextInput that has a child which is an input field. First, we start by creating a ref
with the line of code below:
We pass our ref down to <TextInput ref={inputRef}> by specifying it as a JSX attribute. React then forwards the ref to
the forwardRef() function as a second argument. Next, We forward this ref argument down to <input ref={ref}>. The value of the
DOM node can now be accessed at inputRef.current.
↥
Problem: If you don't name the render function or not using displayName property then it will appear as "ForwardRef" in the
DevTools,
Solution: If you name the render function then it will appear as "ForwardRef(myFunction)"
Example:
function App() {
return (
<div className="App">
<ForwardP style={{ opacity: 0.5 }}>
But my props are <code>null</code> in DevTools
</ForwardP>
</div>
);
}
Using the extends keyword, it allows the current component to access all the component's properties, including the function, and
trigger it from the child component.
Example:
// ParentClass function
callMe() {
console.log("This is a method from parent class");
}
render() {
return false;
}
}
/**
* Child Class
*/
export default class App extends ParentClass {
render() {
return <button onClick={() => this.callMe()}>Call Parent</button>;
}
}
Note: React does not use inheritance except in the initial component class, which extends from the react package.
Example:
/**
* Composition in React
*/
import React, { useState } from "react";
import Name from "./Name";
return (
<form>
<h2>React Composition Example</h2>
<Name name={name} setName={setName} />
<h3>{name}</h3>
</form>
);
}
/**
* Name Component
* @param {*} param0 - name
* @param {*} param1 - setName
*/
export default function Name({ name, setName }) {
return (
<div>
<label>Name: </label>
<input value={name} onChange={(event) => setName(event.target.value)} />
</div>
);
}
⚝
↥
React recommends use of Composition over Inheritance, here is why. Everything in React is a component, and it follows a strong
component based model. This is one of the primary reasons that composition is a better approach than inheritance for code reuse.
1. Inline Styling:
In JSX, JavaScript expressions are written inside curly braces, and since JavaScript objects also use curly braces, the styling in the
example above is written inside two sets of curly braces {{}}. Since the inline CSS is written in a JavaScript object, properties with
two names, like background-color, must be written with camel case syntax:
Example:
/**
* Inline Styling
*/
class HeaderComponent extends React.Component {
render() {
return (
<div>
<h1 style={{backgroundColor: "lightblue"}}>Header Component Style!</h1>
<p>Add a little style!</p>
</div>
);
}
}
2. JavaScript Object:
We can also create an object with styling information, and refer to it in the style attribute:
Example:
/**
* JavaScript Object
*/
class HeaderComponent extends React.Component {
render() {
const mystyle = {
color: "white",
backgroundColor: "DodgerBlue",
padding: "10px",
fontFamily: "Arial"
};
return (
<div>
<h1 style={mystyle}>Header Component Style!</h1>
<p>Add a little style!</p>
</div>
);
}
}
3. CSS Stylesheet:
You can write your CSS styling in a separate file, just save the file with the .css file extension, and import it in your application.
Example:
/**
* App.css
*/
body {
background-color: #282c34;
color: white;
padding: 40px;
font-family: Arial;
text-align: center;
}
/**
* CSS Stylesheet
*/
import './App.css';
4. CSS Modules:
CSS Modules are convenient for components that are placed in separate files
Example:
/**
* mystyle.module.css
*/
.bigblue {
color: DodgerBlue;
padding: 40px;
font-family: Arial;
text-align: center;
}
/**
* CSS Modules
*/
import styles from './mystyle.module.css';
render() {
const isRed = this.state.isRed
const box = {
color: "green",
fontSize: '23px'
}
const shadow = {
background: "orange",
boxShadow: "1px 1px 1px 1px #cccd"
}
↥
Q. What is the benefit of styles modules?
CSS module is a CSS file in which all class names and animation names are scoped locally by default. In the React application, we
usually create a single .css file and import it to the main file so the CSS will be applied to all the components.
But using CSS modules helps to create separate CSS files for each component and is local to that particular file and avoids class
name collision.
render(
<div>
<Button>A black button, like all buttons</Button>
<WhiteButton>A white button</WhiteButton>
</div>
)
It turns defined values into animated values. It does this in two ways, either by overwriting the existing props with a different set of
props on component re-render or by passing an updater function that returns a different set of props that is then used to update
the props using set.
Example:
/**
* useSpring()
*/
import React from "react";
import "./styles.css";
import { useSpring, animated } from "react-spring";
2. useSpring()
It works kind of like a mix between useSpring() and useTransition() in that it takes an array, maps over it, and uses the from and to
properties to assign the animation. For our styles we can just pass in the values from each item in our array.
Example:
/**
* useSprings()
*/
import React, { useState } from "react";
import { animated, useSprings } from "react-spring";
const items = [
{ color: "red", opacity: 1 },
{ color: "blue", opacity: 0.6 },
{ color: "green", opacity: 0.2 }
];
return (
<div>
{springs.map((animation) => (
<animated.h1 style={animation}>Hello World</animated.h1>
))}
<button onClick={() => toggle(!on)}>Click Here</button>
</div>
);
}
3. useTrail()
It allows to create an effect similar to both useSpring() and useSprings(), it will allow us to attach an animation to multiple items but
instead of being executed at the same time, they will be executed one after the other. It just takes a number for how many we want
and the style object.
Example:
/**
* useTrail()
*/
import React, { useState } from "react";
import { animated, useTrail } from "react-spring";
return (
<div>
{springs.map((animation, index) => (
<animated.h1 style={animation} key={index}>
Hello World
</animated.h1>
))}
<button onClick={() => toggle(!on)}>Click Here</button>
</div>
);
}
4. useTransition()
It allows to create an animated transition group. It takes in the elements of the list, their keys, and lifecycles. The animation is
triggered on appearance and disappearance of the elements.
Example:
return (
<div>
{transition.map(({ item, key, props }) => (
item && <animated.div style={props} >Hello world</animated.div>
))}
5. useChain()
It allows to set the execution sequence of previously defined animation hooks. To do this, we use refs, which will subsequently
prevent the independent execution of the animation.
Example:
return (
<div>
{trail.map((animation, index) => (
<animated.h1 style={{ ...animation, ...spring }} key={index}>Hello World</animated.h1>
))}
.DottedBox {
margin: 40px;
border: 5px dotted pink;
}
.DottedBox_content {
font-size: 15px;
text-align: center;
}
2. Inline styling
In React, inline styles are not specified as a string. Instead they are specified with an object whose key is the camelCased version of
the style name, and whose value is the style's value, usually a string.
const divStyle = {
margin: '40px',
border: '5px solid pink'
}
const pStyle = {
fontSize: '15px',
textAlign: 'center'
}
We can create a variable that stores style properties and then pass it to the element like style={nameOfvariable}
We can also pass the styling directly style={{color: 'pink'}}
3. CSS Modules
A CSS Module is a CSS file in which all class names and animation names are scoped locally by default.
:local(.container) {
margin: 40px;
border: 5px dashed pink;
}
:local(.content) {
font-size: 15px;
text-align: center;
}
we import css file import styles './DashedBox.css', then we access to className as we access to object.
4. Styled-components
Styled-components is a library for React and React Native that allows to use component-level styles in component application that
are written with a mixture of JavaScript and CSS
ReactCSSTransitionGroup is a high-level API based on ReactTransitionGroup and is an easy way to perform CSS transitions and
animations when a React component enters or leaves the DOM. It has four components that display transitions from one component
state to another using a declarative API used for mounting and unmounting of components:
1. Transition
2. CSSTransition
3. SwitchTransition
4. TransitionGroup
Example:
handleAdd() {
const newItems = this.state.items.concat([
prompt('Enter some text')
])
this.setState({items: newItems})
}
handleRemove(i) {
let newItems = this.state.items.slice()
newItems.splice(i, 1)
this.setState({items: newItems})
}
render() {
const items = this.state.items.map((item, i) => (
<div key={item} onClick={() => this.handleRemove(i)}>
{item}
</div>
))
return (
<div>
<button onClick={this.handleAdd}>Add Item</button>
<ReactCSSTransitionGroup
transitionName="example"
transitionEnterTimeout={500}
transitionLeaveTimeout={300}>
{items}
</ReactCSSTransitionGroup>
</div>
)
}
}
In this component, when a new item is added to ReactCSSTransitionGroup it will get the example-enter CSS class and the example-
enter-active CSS class added in the next tick. This is a convention based on the transitionName prop.
↥
function MyPureComponent(props) {
return (
<div>
<Button>Normal</Button>
<Button primary>Primary</Button>
</div>
)
}
Configure i18next
Create a new file i18n.js beside your index.js containing following content:
/**
* i18next Component
*/
import i18n from "i18next";
import LanguageDetector from "i18next-browser-languagedetector";
import { initReactI18next } from "react-i18next";
i18n
.use(LanguageDetector)
.use(initReactI18next)
.init({
// we init with resources
resources: {
en: {
translations: {
"Welcome to React": "Welcome to React and react-i18next"
}
},
hi: {
translations: {
"Welcome to React": "React और react-i18next में आपका स्वागत है"
}
}
},
fallbackLng: "en",
debug: true,
interpolation: {
escapeValue: false
}
});
We pass the i18n instance to react-i18next which will make it available for all the components via the context api.
/**
* useTranslation() in React
*/
import React from "react";
import { useTranslation } from "react-i18next";
return (
<>
<h2>{t("Welcome to React")}</h2>
<button onClick={() => changeLanguage("en")}>English</button>
<button onClick={() => changeLanguage("hi")}>Hindi</button>
</>
);
}
Reference:
https://react.i18next.com/guides/quick-start
Process:
1. Add a test
2. Run all tests and see if the new test fails (red)
3. Write the code to pass the test (green)
4. Run all tests
5. Refactor
6. Repeat
Pros:
Cons:
1. Takes longer to develop (but it can save time in the long run)
2. Testing edge cases is hard
3. Mocking, faking, and stubbing are all even harder
Jest is a JavaScript unit testing framework, used by Facebook to test services and React applications. Jest acts as a test
runner, assertion library, and mocking library.
Jest also provides Snapshot testing, the ability to create a rendered snapshot of a component and compare it to a previously
saved snapshot. The test will fail if the two do not match.
2. Enzyme
Enzyme is a JavaScript Testing utility for React that makes it easier to assert, manipulate, and traverse your React Components
output. Enzyme, created by Airbnb, adds some great additional utility methods for rendering a component (or multiple
components), finding elements, and interacting with elements.
/**
* App.js
*/
import React, { useState } from "react";
return (
<>
<button onClick={incrementCounter}>Click Me</button>
<h2 data-testid="counter">{counter}</h2>
</>
);
}
/**
* App.test.js
*/
import React from "react";
import { shallow } from "enzyme";
import App from "./App";
Reference:
https://jestjs.io/docs/en/tutorial-react
https://enzymejs.github.io/enzyme/
2. Truthiness:
3. Numbers:
toBeGreaterThan() expect(2).toBeGreaterThan(1)
toBeGreaterThanOrEqual() expect(1).toBeGreaterThanOrEqual(1)
toBeLessThan() expect(1).toBeLessThan(2)
toBeLessThanOrEqual() expect(1).toBeLessThanOrEqual(1)
toEqual() expect(NaN).toEqual(expect.any(Number))
4. Strings:
Method Example Description
toEqual() expect('string').toEqual(expect.any(String))
toMatch() expect('coffee').toMatch(/ff/)
not.toMatch() expect('pizza').not.toMatch('coffee')
5. Arrays:
toEqual() expect([]).toEqual(expect.any(Array))
6. Objects:
7. Exceptions:
toThrow() expect(fn).toThrow()
toThrowErrorMatchingSnapshot() expect(fn).toThrowErrorMatchingSnapshot()
This package makes it easy to grab a snapshot of the platform view hierarchy (similar to a DOM tree) rendered by a ReactDOM or
React Native without using a browser or jsdom.
Example:
function Link(props) {
return <a href={props.page}>{props.children}</a>;
}
console.log(testRenderer.toJSON());
// { type: 'a',
// props: { href: 'https://www.facebook.com/' },
// children: [ 'Facebook' ] }
act()
mockComponent()
isElement()
isElementOfType()
isDOMComponent()
renderIntoDocument()
Simulate()
act()
To prepare a component for assertions, wrap the code rendering it and performing updates inside an act() call. This makes your test
run closer to how React works in the browser.
beforeEach(() => {
container = document.createElement('div')
document.body.appendChild(container)
})
afterEach(() => {
document.body.removeChild(container)
container = null
})
Essentially, this package makes it easy to grab a snapshot of the platform view hierarchy (similar to a DOM tree) rendered by a React
DOM or React Native component without using a browser or jsdom.
Example:
/**
* Snapshot tests are a useful when UI does not change frequently.
*
* A typical snapshot test case for a mobile app renders a UI component, takes a snapshot,
* then compares it to a reference snapshot file stored alongside the test.
*/
describe('APP Component', () => {
let wrapper
beforeEach(() => {
wrapper = render(<Header/>)
})
Q. What is React.cloneElement?
The React.cloneElement() function returns a copy of a specified element. Additional props and children can be passed on in the
function. This function is used when a parent component wants to add or modify the prop(s) of its children.
Example:
Read, add, edit, remove props in any of the React Elements outputted by render
Read, and modify the React Elements tree outputted by render
Conditionally display the elements tree
Wrapping the element's tree for styling purposes.
react-window and react-virtualized are popular windowing libraries. They provide several reusable components for displaying lists,
grids, and tabular data.
Example: react-window
function renderRow(props) {
const { index, style } = props;
return (
<ListItem button style={style} key={index}>
<ListItemText primary={`Item ${index + 1}`} />
</ListItem>
);
}
return (
<div>
<FixedSizeList height={400} width={200} itemSize={46} itemCount={100000}>
{renderRow}
</FixedSizeList>
</div>
);
}
Experience performance problems with a specific component, the React DevTools Profiler is usually the first place to look.
2. shouldComponentUpdate() method
React provides a simple lifecycle method to indicate if a component needs re-rendering and that is, shouldComponentUpdate()
which is triggered before the re-rendering process starts. The default implementation of this function returns true.
If you know that in some situations your component doesn't need to update, you can return false from shouldComponentUpdate()
instead, to skip the whole rendering process, including calling render() on component.
shouldComponentUpdate(nextProps, nextState) {
return false;
}
Functional components reduce the bundle size as they are better at minifying than classes and they prevent construction of class
instances.
Pure Components in React are the components which do not re-renders when the value of state and props has been updated with
the same values. Pure Components restricts the re-rendering ensuring the higher performance of the Component.
4. React.memo()
React.memo is a higher order component. It's similar to React.PureComponent but for function components instead of classes.
const MyComponent = React.memo(function MyComponent(props) {
/* render using props */
})
If your function component renders the same result given the same props, you can wrap it in a call to React.memo for a performance
boost in some cases by memoizing the result. This means that React will skip rendering the component, and reuse the last rendered
result.
React.memo only checks for prop changes. If your function component wrapped in React.memo has a useState or useContext Hook in
its implementation, it will still rerender when state or context change.
5. Virtualizing Long Lists
In order to address the issue with our long chat feed, the React team recommends a technique called windowing. This technique
only renders the portion of the list that is visible to the user (+/- a given offset) in order to reduce the time to render. As the user
scrolls, new list items are retrieved and rendered. react-window and react-virtualized are two libraries that provide components to
help with list virtualization.
6. Use the Production Build:
React's production build improves react apps performance. The file size of the production build is significantly smaller, which means
that the page loads faster as the browser has to download, parse, and execute fewer elements.
Reference:
https://reactjs.org/docs/optimizing-performance.html
/**
* Polling in React
*/
import React, { useState, useEffect } from "react";
useEffect(() => {
const interval = setInterval(() => {
setSeconds((seconds) => seconds + 1);
}, 1000);
return () => clearInterval(interval);
}, []);
The example above shows a React component, IntervalExample, scheduling a new interval once it mounts to the DOM. The interval
increments the seconds state value by one, every second.
MVC - Model-View-Controller
MVP - Model-View-Presenter
MVVM - Model-View-ViewModel
MVW / MV* / MVx - Model-View-Whatever
HMVC - Hierarchical Model-View-Controller
MMV - Multiuse Model View
MVA - Model-View-Adapter
MVW is easy to manage in a simple application, with few models/controllers. But we can easily start to witness problems as we grow
in size with the following problems:
1. There is need when models/controllers communicate with each others (through a service layer probably), and these
modules changes the states of each others, and the more controllers, the more easy to lose control of who changed the
state of a controller.
2. Asynchronous network calls to retrieve data add uncertainty of when the model will be changed or modified, and imagine
the user changing the UI while a callback from asynchronous call comeback, then we will have "nondeterministic" status of
the UI.
3. Change state/model has another layer of complexity which is the mutation. When to consider the state or model is
changed and how to build tools to help recognize the mutation.
4. Adding to that if the application is a collaborative applications, (like google docs for examples) where lots of data changes
happening in real-time.
5. No way to do undo (travel back in time) easily without adding so much extra code.
function showTime() {
const element = (
<div>
<h2>Current Time is: {new Date().toLocaleTimeString()}</h2>
</div>
);
ReactDOM.render(element, document.getElementById("root"));
}
setInterval(showTime, 1000);
⚝
↥
Example:
/**
* React Render()
*/
import React from "react";
/**
* Message Component
* @param {*} props
*/
function Message(props) {
return <h2>{props.name}</h2>;
}
/**
* App Component
*/
export default class App extends React.Component {
state = {
showMessage: false
};
render() {
return (
<div>
<button onClick={() => this.setState({ showMessage: true })}> Show Message </button>
<button onClick={() => this.setState({ showMessage: false })}> Hide Message </button>
{this.state.showMessage && <Message name="Hello React!" />}
</div>
);
}
}
Internally, React will create an instance of App and will eventually call the render() method to get the first set of instructions for what
it needs to build in the DOM. Anytime React calls the render method of a class-based component, we call that a render.
⚝
Type checking means ensuring that the type of a property (variable, object, function, string) in a programming language is being
used as it should be. It is the process of verifying and enforcing the constraints of types, and it can occur either at compile time or at
runtime. It helps to detect and report errors.
Type checking can be divided into two: static type checking and dynamic type checking.
Dynamic type checking is used in dynamic-typed languages where the type is usually known at runtime. This means that the type of
the variable doesn't need to be explicitly defined.
Flow
Flow is a static type checker for JavaScript apps that aims to find and eliminate problems as you code. Designed by the Facebook
team for JavaScript developers, it's a static type checker that catches common errors in your application before they run.
Integrating Flow
# Add Dependency
npm install --save-dev flow-bin
The next thing to do is add Flow to the "scripts" section of your package.json so that Flow can be used in the terminal. In the
package.json file, add the code snippet below.
"scripts": {
"flow": "flow",
}
Finally, for the Flow setup, run any of the commands below:
This will help to create a Flow configuration file that should be committed. The Flow config file helps to determine the files that Flow
should work with and what should be ignored.
A fiber is a JavaScript object that contains information about a component, its input, and output. At any time, a component instance
has at most two fibers that correspond to it: the current fiber and the work-in-progress fiber. A fiber can be defined as a unit of
work.
UNSAFE_componentWillMount()
UNSAFE_componentWillReceiveProps()
getDerivedStateFromProps()
shouldComponentUpdate()
UNSAFE_componentWillUpdate()
render()
getSnapshotBeforeUpdate()
componentDidMount()
componentDidUpdate()
componentWillUnmount()
The earlier whole reconciliation process was synchronous (recursive), but in Fiber, it is divided into two phases. Render phase (a.k.a.
Reconciliation phase) is asynchronous, so three of the lifecycle methods were marked unsafe because putting the code with side-
effects inside these methods can cause problems, as lifecycle methods of different components are not guaranteed to fire in a
predictable order.
React Fiber uses requestIdleCallback() to schedule the low priority work and requestAnimationFrame() to schedule high priority
work.
Problems with Current Implementation:
Fiber is currently available for use but it runs in compatibility mode with the current implementation.
↥
Q. Does the static object work with ES6 classes in
React?
Although statics only works for React.createClass(), you can still write static methods in ES6 notation. If you are using ES7, then you
can also write static properties.
class Component extends React.Component {
static propTypes = {
...
}
static someMethod(){
}
}
Calls to Hooks are either inside a PascalCase function (assumed to be a component) or another useSomething function
(assumed to be a custom Hook).
Hooks are called in the same order on every render.
// ESLint configuration
{
"plugins": [
// ...
"react-hooks"
],
"rules": {
// ...
"react-hooks/rules-of-hooks": "error", // Checks rules of Hooks
"react-hooks/exhaustive-deps": "warn" // Checks effect dependencies
}
}
Service workers depend on two APIs to work effectively: Fetch (a standard way to retrieve content from the network)
and Cache (content storage for application data. This cache is independent from the browser cache or network status).
Service Worker Lifecycle:
Each service worker goes through three steps in its lifecycle: registration, installation and activation.
Registration:
To install a service worker, you need to register it in script. Registration informs the browser where your service worker is located and
lets it know it can start installing in the background.
.then(function(registration) {
// Successful registration
console.log('Registration successful, scope is:', registration.scope);
}).catch(function(err) {
// Failed registration, service worker won\'t be installed
console.log('Service worker registration failed, error:', error);
});
}
Service workers are event driven. The installation and activation processes fire off corresponding install and activate events to which
the service workers can respond.
With the service worker registered, the first time a user hits your PWA, the install event will be triggered and this is where you'll want
to cache the static assets for the page.
// index.js
In React, Each time the DOM updates or data of page changes, a new Virtual DOM representation of the user interface is made. It is
just a lightweight copy or DOM.
Virtual DOM in React has almost same properties like a real DOM, but it can not directly change the content on the page. Working
with Virtual DOM is faster as it does not update anything on the screen at the same time. In a simple way, Working with Virtual DOM
is like working with a copy of real DOM nothing more than that.
When we render a JSX element, each virtual DOM updates. This approach updates everything very quickly. Once the Virtual DOM
updates, React matches the virtual DOM with a virtual DOM copy that was taken just before the update. By Matching the new virtual
DOM with pre-updated version, React calculates exactly which virtual DOM has changed. This entire process is called diffing.
When React knows which virtual DOM has changed, then React updated those objects. and only those object, in the real DOM. React
only updates the necessary parts of the DOM. React's reputation for performance comes largely from this innovation.
DOM stands for "Document Object Model". The HTML DOM provides an interface (API) to traverse and modify the nodes. It contains
methods like getElementById() or removeChild().
The DOM is represented as a tree data structure. Because of that, the changes and updates to the DOM are fast. But after the
change, the updated element and it's children have to be re-rendered to update the application UI. The re-rendering or re-painting
of the UI is what makes it slow.
2. Virtual DOM:
The virtual DOM is only a virtual representation of the DOM. Everytime the state of our application changes, the virtual DOM gets
updated instead of the real DOM.
The Virtual DOM is an abstraction of the HTML DOM. It is lightweight and detached from the browser-specific implementation
details. Since the DOM itself was already an abstraction, the virtual DOM is, in fact, an abstraction of an abstraction.
When new elements are added to the UI, a virtual DOM, which is represented as a tree is created. Each element is a node on this
tree. If the state of any of these elements changes, a new virtual DOM tree is created. This tree is then compared or “diffed” with the
previous virtual DOM tree.
Once this is done, the virtual DOM calculates the best possible method to make these changes to the real DOM. This ensures that
there are minimal operations on the real DOM. Hence, reducing the performance cost of updating the real DOM.
Once the difference is known, React updates only those objects that differ on the actual DOM and the browser re-paints the screen.
The next time state or props changes for a component in the application, a new virtual DOM tree of React elements will be created
and the process will repeat.
The process of checking the difference between the new Virtual DOM tree and the old Virtual DOM tree is called diffing. Diffing is
accomplished by a heuristic O(n) algorithm. During this process, React will deduce the minimum number of steps needed to update
the real DOM, eliminating unnecessary costly changes. This process is also referred to as reconciliation.
Whenever the root elements have different types, React will tear down the old tree and build the new tree from scratch. When
tearing down a tree, old DOM nodes are destroyed. Component instances receive componentWillUnmount().
When building up a new tree, new DOM nodes are inserted into the DOM. Component instances
receive UNSAFE_componentWillMount() and then componentDidMount(). Any state associated with the old tree is lost.
2. DOM Elements Of The Same Type:
When comparing two React DOM elements of the same type, React looks at the attributes of both, keeps the same underlying DOM
node, and only updates the changed attributes.
Example: By comparing these two elements, React knows to only modify the className on the underlying DOM node.
<div className="before" title="React JS" />
When a component updates, the instance stays the same, so that state is maintained across renders. React updates the props of the
underlying component instance to match the new element, and
calls UNSAFE_componentWillReceiveProps(), UNSAFE_componentWillUpdate() and componentDidUpdate() on the underlying instance.
Recursing On Children
By default, when recursing on the children of a DOM node, React just iterates over both lists of children at the same time and
generates a mutation whenever there's a difference.
For example, when adding an element at the end of the children, converting between these two trees works well:
<ul>
<li>first</li>
<li>second</li>
</ul>
<ul>
<li>first</li>
<li>second</li>
<li>third</li>
</ul>
React will match the two <li>first</li> trees, match the two <li>second</li> trees, and then insert the <li>third</li> tree.
Keys
When children have keys, React uses the key to match children in the original tree with children in the subsequent tree. For example,
adding a key to our inefficient example above can make the tree conversion efficient:
<ul>
<li key="2015">Duke</li>
<li key="2016">Villanova</li>
</ul>
<ul>
<li key="2014">Connecticut</li>
<li key="2015">Duke</li>
<li key="2016">Villanova</li>
</ul>
As a developer we are creating tree of components, react then takes this tree, process it and we get a Virtual DOM that it's kept in
memory. When there is an update in our application (e.g. change in state or props) react will take the updated Virtual DOM and
compares it with the old one Virtual DOM, then decides what and how should be changed. This procedure is repeated all over again.
Also synced versions between Virtual DOM and "real" DOM are served by libraries such as ReactDOM. React needs to be very fast at
comparing those trees, so it uses heuristic algorithm with complexity of O(n), so this says for 1000 nodes we need 1000
comparasions. This approach is used instead of state of the art algorithms, which have complexity of O(n^3) => for 1000 nodes we
need 1 bilion comparasions.
Example: Let's build a simple component that adds two numbers. The numbers will be entered in an input field.
state = {
result: '',
en 1: '',
en 2: ''
}
render() {
const { en 1, en 2, result } = this.state
return(
<div>
<div>
Result: { result }
</div>
<span><input type='text' onChange={this.handleEn 1} /></span>
<br />
<br />
<span><input type='text' onChange={this.handleEn 2} /></span>
<div>
<button onClick={this.handleAddition} type='submit'>Add</button>
</div>
</div>
)
}
}
When an en is made in the first input field, React creates a new tree. The new tree which is the virtual DOM will contain the new
state for en 1. Then, React compares the virtual DOM with the old DOM and, from the comparison, it figures out the difference
between both DOMs and makes an update to only the part that is different. A new tree is created each time the state of App
component changes — when a value is entered in either of the inputs field, or when the button is clicked.
Normally, a functional or a class component renders a tree of React elements (usually generated from JSX). The React element
defines how the DOM of the parent component should look.
ReactDOM.createPortal(child, container)
Features:
It transports its children component into a new React portal which is appended by default to document.body.
It can also target user specified DOM element.
It supports server-side rendering
It supports returning arrays (no wrapper div's needed)
It uses <Portal /> and <PortalWithState /> so there is no compromise between flexibility and convenience.
Installation:
Example:
/**
* React Portal
*/
import PortalExample from "./PortalExample.js";
/**
* Portal Component
*/
import React from "react";
import ReactDOM from "react-dom";
Now, open the Index.html file and add a <div id="portal-root"></div> element to access the child component outside the root
node.
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<title>React App using Portal</title>
</head>
<body>
<noscript>It is required to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<div id="portal-root"></div>
</body>
</html>
Q. What is ReactDOMServer?
The ReactDOMServer object enables you to render components to static markup. Typically, it's used on a Node server:
// ES modules
import ReactDOMServer from 'react-dom/server'
// CommonJS
var ReactDOMServer = require('react-dom/server')
The Server-side rendering (SSR) is a popular technique for rendering a client-side single page application (SPA) on the server and
then sending a fully rendered page to the client. This allows for dynamic components to be served as static HTML markup.
It allows your site to have a faster first page load time, which is the key to a good user experience
This approach can be useful for search engine optimization (SEO) when indexing does not handle JavaScript properly.
It is great when people share a page of your site on social media, as they can easily gather the metadata needed to nicely
share the link (images, title, description..)
Example:
All the content inside the build folder is going to be served as-is, statically by Express.
// server/server.js
router.use(
express.static(path.resolve(__dirname, '..', 'build'), { maxAge: '30d' })
)
// app.use(express.static('./build'))
app.listen(PORT, () => {
console.log(`SSR running on port ${PORT}`)
})
call ReactDOM.hydrate(), which is the same but has the additional ability to attach event listeners to existing markup once React
loads:
All the Node.js code needs to be transpiled by Babel, as server-side Node.js code does not know anything about JSX, nor ES
Modules (which we use for the include statements).
Babel Package
require('./server')
Build the React application, so that the build/ folder is populated and run this:
# Build App
npm run build
Linting tools like ESLint can be used with plugins such as eslint-plugin-jsx-a11y to analyse React projects at a component level.
Static analysis tools run very quickly, so they bring a good benefit at a low cost.
2. Browser Tools:
Browser accessibility tools such as aXe and Google Lighthouse perform automated accessibility at the app level. This can discover
more real-world issues, because a browser is used to simulate the way that a user interacts with a website.
↥
# 1. REDUX OVERVIEW
Q. What is Redux?
Redux is a state management tool. While it is mostly used with React, it can be used with any other JavaScript framework or library.
With Redux, the state of your application is kept in a store, and each component can access any state that it needs from this store.
Architecture
In Redux architecture, application event is denoted as an Action, which is dispatched to the reducer, the pure function. Then reducer
updates the centralized store with new data based on the kind of action it receives. Store creates a new state and sends an update to
view. At that time, the view was recreated to reflect the update.
There is a central store that holds the entire state of the application. Each component can access the stored state without having to
send down props from one component to another. There are three building parts: actions, store, and reducers.
State is stored together in a single place called the ‘store.’ While you do not need to store all the state variables in the ‘store,’ it is
especially important to when state is being shared by multiple components or in a more complex architecture. It also allows you to
call state data from any component easily.
2. Predictability
Redux is “a predictable state container for Javascript apps.” Because reducers are pure functions, the same result will always be
produced when a state and action are passed in.
3. Maintainability
Redux provides a strict structure for how the code and state should be managed, which makes the architecture easy to replicate and
scale for somebody who has previous experience with Redux.
Redux makes it easy to test and debug your code since it offers powerful tools such as Redux DevTools in which you can time travel
to debug, track your changes, and much more to streamline your development process.
Action is static information about the event that initiates a state change. When you update your state with Redux, you always start
with an action. Actions are in the form of Javascript objects, containing a type and an optional payload. Actions are sent using
the store.dispatch() method. Actions are created via an action creator.
Action creators are simple functions that help to create actions. They are functions that return action objects, and then, the returned
object is sent to various reducers in the application.
2. Reducers in Redux
Reducers are pure functions that take the current state of an application, perform an action, and return a new state. These states are
stored as objects, and they specify how the state of an application changes in response to an action sent to the store.
It is based on the reduce function in JavaScript, where a single value is calculated from multiple values after a callback function has
been carried out.
combine multiple reducers: The combineReducers() helper function turns an object whose values are different reducing functions
into a single reducing function you can pass to createStore.
Syntax:
3. Store in Redux
A Store is an object that holds the whole state tree of your application. The Redux store is the application state stored as objects.
Whenever the store is updated, it will update the React components subscribed to it. The store has the responsibility of storing,
reading, and updating state.
When using Redux with React, states will no longer need to be lifted up; thus, it makes it easier to trace which action causes any
change.
4. Dispatch
Dispatch is a method that triggers an action with type and payload to Reducer.
store.dispatch()
5. Subscribe
store.subscribe()
6. Provider
The Provider is a component that has a reference to the Store and provides the data from the Store to the component it wraps.
7. Connect
8. Middleware
Middleware is the suggested way to extend Redux with custom functionality. Middlewares are used to dispatch async functions. We
configure Middleware's while creating a store.
Syntax:
Example:
/**
* React Redux Simple Example
*/
import React from "react";
import "./styles.css";
import { signIn, signOut } from "./actions";
import { useSelector, useDispatch } from "react-redux";
export default function App() {
const isLogged = useSelector((state) => state.isLogged);
const dispatch = useDispatch();
return (
<div className="App">
<h1>React Redux Example</h1>
<button onClick={() => dispatch(signIn())}>SignIn</button>
<button onClick={() => dispatch(signOut())}>SignOut</button>
/**
* Actions
*/
export const signIn = () => {
return {
type: "SIGN_IN"
};
};
/**
* Reducers
*/
import { combineReducers } from "redux";
Container is an informal term for a React component that is connect-ed to a redux store. Containers receive Redux state updates
and dispatch actions, and they usually don't render DOM elements; they delegate rendering to presentational child components.
Example:
this.state = {
images: []
};
}
componentDidMount() {
fetch('/api/current_user/image_list')
.then(response => response.json())
.then(images => this.setState({images}));
}
render() {
return (
<div className="image-list">
{this.state.images.map(image => {
<div className="image">
<img src={book.image_url} />
</div>
})}
</div>
)
}
}
2. Presentational Components
Example:
# 2. REDUX SETUP
Installation:
React Redux 8.x requires React 16.8.3 or later / React Native 0.59 or later, in order to make use of React Hooks.
Folder structure:
Reference:
https://react-redux.js.org/introduction/getting-started
Components - Contains all 'dumb' or presentational components, consisting only of HTML and styling.
Containers - Contains all corresponding components with logic in them. Each container will have one or more component
depending on the view represented by the container.
Actions - All Redux actions
Reducers - All Redux reducers
API - API connectivity related code. Handler usually involves setting up an API connector centrally with authentication and
other necessary headers.
Utils - Other logical codes that are not React specific. For example, authUtils would have functions to process the JWT
token from the API to determine the user scopes.
Store - Used for redux store initialization.
Example:
└── src
├── actions
│ ├── articleActions.js
│ ├── categoryActions.js
│ └── userActions.js
├── api
│ ├── apiHandler.js
│ ├── articleApi.js
│ ├── categoryApi.js
│ └── userApi.js
├── components
│ ├── ArticleComponent.jsx
│ ├── ArticleListComponent.jsx
│ ├── CategoryComponent.jsx
│ ├── CategoryPageComponent.jsx
│ └── HomePageComponent.jsx
├── containers
│ ├── ArticleContainer.js
│ ├── CategoryPageContainer.js
│ └── HomePageContainer.js
├── index.js
├── reducers
│ ├── articleReducer.js
│ ├── categoryReducer.js
│ └── userReducer.js
├── routes.js
├── store.js
└── utils
└── authUtils.js
Redux has five main entities. Action Creators, Dispatching Function, Reducers, State and Store.
The state of your whole application is stored in an object tree inside a single store.
This makes it easy to create universal apps, as the state from your server can be serialized and hydrated into the client with no extra
coding effort. A single state tree also makes it easier to debug or inspect an application; it also enables you to persist your app's
state in development, for a faster development cycle.
Example:
console.log(store.getState())
/* Prints
{
visibilityFilter: 'SHOW_ALL',
todos: [
{
text: 'Consider using Redux',
completed: true,
},
{
text: 'Keep all state in a single tree',
completed: false
}
]
}
*/
2. State is read-only
The only way to change the state is to emit an action, an object describing what happened.
This ensures that neither the views nor the network callbacks will ever write directly to the state. Instead, they express an intent to
transform the state. Because all changes are centralized and happen one by one in a strict order, there are no subtle race conditions
to watch out for.
Example:
store.dispatch({
type: 'COMPLETE_TODO',
index: 1
})
store.dispatch({
type: 'SET_VISIBILITY_FILTER',
filter: 'SHOW_COMPLETED'
})
To specify how the state tree is transformed by actions, you write pure reducers.
Reducers are just pure functions that take the previous state and an action, and return the next state. Remember to return new state
objects, instead of mutating the previous state. You can start with a single reducer, and as your app grows, split it off into smaller
reducers that manage specific parts of the state tree.
In React-Redux applications, when your Redux is a single source of truth, it means that the only way to change your data in UI is to
dispatch redux action which will change state within redux reducer. And your React components will watch this reducer and if that
reducer changes, then UI will change itself too. But never other way around, because Redux state is single source of truth.
A practical example would be that you have Redux store which contains items you want to display. In order to change list of items to
be displayed, you don't change this data anywhere else other than store. And if that is changed, everything else related to it, should
change as well.
Redux offers a solution for storing all your application state in one place, called a store.
Components then dispatch state changes to the store, not directly to other components.
The components that need to be aware of state changes can subscribe to the store.
The store can be thought of as a "middleman" for all state changes in the application.
With Redux involved, components don't communicate directly with each other. Rather, all state changes must go through
the single source of truth, the store.
Core Principal
1. Single Source of Truth: The state of your whole application is stored in an object tree within a single store.
2. State Is Read-Only: The only way to change the state is to dispatch an action, an object describing what happened.
3. Changes Are Made With Pure Functions: To specify how the state tree is transformed by actions, you write pure reducers.
Redux Workflow
Redux allows you to manage the state of the application using Store. A child component can directly access the state from the Store.
When UI Event triggers (OnClick, OnChange, etc) it can dispatch Actions based on the event.
Reducers process Actions and return a new state as an Object.
The new state of the whole application goes into a single Store.
Components can easily subscribe to the Store.
↥
# 4. REDUX STORE
Example:
/**
* store in Redux
*/
import { createRoot } from "react-dom/client";
import { Provider } from "react-redux";
import { createStore } from "redux";
import rootReducer from "./reducers";
import App from "./components/App";
// create store
const store = createStore(rootReducer);
root.render(
<provider store="{store}">
<App />
</provider>
);
When using Redux with React, states will no longer need to be lifted up; thus, it makes it easier to trace which action causes any
change.
Here, we are creating the store and exporting it. This will make it available to other files. Here we'll see an api file making a call
where we need to pass a JWT token to the server:
import store from './store'
It's simple to get access to the store inside a React component – no need to pass the store as a prop or import it, just use
the connect() function from React Redux, and supply a mapStateToProps() function that pulls out the data.
import React from 'react'
import { connect } from 'react-redux'
import * as api from 'api'
export connect(mapStateToProps)(ItemList)
Some common rules for determining what kind of data should be put into Redux:
Use mapStateToProps(): It maps the state variables from your store to the props that you specify.
Connect props to container: The object returned by the mapStateToProps function is connected to the container.
Example:
function mapStateToProps(state) {
return { containerData: state.data }
}
# 5. REDUX ACTIONS
Q. What is an action in Redux?
Actions are plain JavaScript objects or payloads of information that send data from your application to your store. They are the only
source of information for the store. Actions must have a type property that indicates the type of action being performed.
An action is an object that contains two keys and their values. The state update that happens in the reducer is always dependent on
the value of action.type.
Example:
const action = {
type: 'NEW_CONTACT',
name: 'Alex K',
location: 'Lagos Nigeria',
email: '[email protected]'
}
There is typically a payload value that contains what the user is sending and would be used to update the state of the application. It
is important to note that action.type is required, but action.payload is optional. Making use of payload brings a level of structure to
how the action object looks like.
An action type is a string that simply describes the type of an action. They're commonly stored as constants or collected in
enumerations to help reduce typos.
Example:
2. Action:
An action is like a message that we send (i.e. dispatch) to our central Redux store. It can literally be anything. But ideally we want to
stick to an agreed-upon pattern. And the standard pattern is as follows (this is a TypeScript type declaration):
Example:
type Action = {
type: string; // Actions MUST have a type
payload?: any; // Actions MAY have a payload
meta?: any; // Actions MAY have meta information
error?: boolean; // Actions MAY have an error field
// when true, payload SHOULD contain an Error
}
An action to fetch the user named "Ram" might look something like this
{
type: 'GET_USER_DETAILS_REQUEST',
payload: 'Ram'
}
3. Action Creator:
When writing basic Redux, an action creator simply returns an action. You would typically dispatch the action to your store
immediately.
Example:
export const getUserDetailsRequest = id => ({
type: Actions.GET_USER_DETAILS_REQUEST,
payload: id,
})
store.dispatch(getUserDetailsRequest('Ram'))
Although, realistically, you'll be doing this via dispatch properties that are passed into a React component like this:
// ES6
export const mapDispatchToProps = dispatch => ({
onClick: () => dispatch(getUserDetailsRequest('Ram'))
})
/**
* Dispatch an action on load
*/
class App extends Component {
componentDidMount() {
this.props.fetchData()
}
render() {
return this.props.isLoaded
? <div>{'Loaded'}</div>
: <div>{'Not Loaded'}</div>
}
}
# 6. REDUX REDUCERS
It is based on the reduce function in JavaScript, where a single value is calculated from multiple values after a callback function has
been carried out.
Example:
if (user.password == action.password) {
return {
...user,
login_status: "LOGGED IN"
}
}
});
default:
return state;
}
}
1. State
State changes are based on a user's interaction, or even something like a network request. If the application's state is managed by
Redux, the changes happen inside a reducer function — this is the only place where state changes happen. The reducer function
makes use of the initial state of the application and something called action, to determine what the new state will look like.
Syntax:
2. State Parameter
The state parameter that gets passed to the reducer function has to be the current state of the application. In this case, we're calling
that our initialState because it will be the first (and current) state and nothing will precede it.
contactReducer(initialState, action)
Example:
Let's say the initial state of our app is an empty list of contacts and our action is adding a new contact to the list.
const initialState = {
contacts: []
}
3. Action Parameter
An action is an object that contains two keys and their values. The state update that happens in the reducer is always dependent on
the value of action.type.
const action = {
type: 'NEW_CONTACT',
name: 'Alex K',
location: 'Lagos Nigeria',
email: '[email protected]'
}
There is typically a payload value that contains what the user is sending and would be used to update the state of the application. It
is important to note that action.type is required, but action.payload is optional. Making use of payload brings a level of structure to
how the action object looks like.
4. Updating State
The state is meant to be immutable, meaning it shouldn't be changed directly. To create an updated state, we can make use
of Object.assign() or opt for the spread operator.
Example:
const contactReducer = (state, action) => {
switch (action.type) {
case 'NEW_CONTACT':
return {
...state, contacts:
[...state.contacts, action.payload]
}
default:
return state
}
}
This ensures that the incoming state stays intact as we append the new item to the bottom.
const initialState = {
contacts: [{
name: 'Alex K',
age: 26
}]
}
handleSubmit = e => {
e.preventDefault()
const action = {
type: "NEW_CONTACT",
payload: {
name: this.name.current.value,
age: this.age.current.value
}
}
const newState = contactReducer(this.state, action)
this.setState(newState)
}
render() {
const { contacts } = this.state
return (
<div className="box">
<div className="content">
<pre>{JSON.stringify(this.state, null, 2)}</pre>
</div>
<div className="field">
<form onSubmit={this.handleSubmit}>
<div className="control">
<input className="input" placeholder="Full Name" type="text" ref={this.name} />
</div>
<div className="control">
<input className="input" placeholder="Age" type="number" ref={this.age} />
</div>
<div>
<button type="submit" className="button">Submit</button>
</div>
</form>
</div>
</div>
)
}
}
ReactDOM.render(
<App />,
document.getElementById('root')
)
Redux simply checks whether the old object is the same as the new object by comparing the memory locations of the two objects.
So if you mutate the old object's property inside a reducer, the "new state" and the "old state" will both point to the same object.
Hence Redux thinks nothing has changed! So this won't work.
In Redux reducer, we can split some of our reducer logic out into another function, and call that new function from the parent
function. These new functions would typically fall into one of three categories:
1. Small utility functions containing some reusable chunk of logic that is needed in multiple places (which may or may not be
actually related to the specific business logic)
2. Functions for handling a specific update case, which often need parameters other than the typical (state, action) pair
3. Functions which handle all updates for a given slice of state. These functions do generally have the typical (state, action)
parameter signature
These terms will be used to distinguish between different types of functions and different use cases:
reducer: any function with the signature (state, action) -> newState (ie, any function that could be used as an argument
to Array.prototype.reduce)
root reducer: the reducer function that is actually passed as the first argument to createStore. This is the only part of the
reducer logic that must have the (state, action) -> newState signature.
slice reducer: a reducer that is being used to handle updates to one specific slice of the state tree, usually done by
passing it to combineReducers
case function: a function that is being used to handle the update logic for a specific action. This may actually be a reducer
function, or it may require other parameters to do its work properly.
higher-order reducer: a function that takes a reducer function as an argument, and/or returns a new reducer function as
a result (such as combineReducers, or redux-undo).
Benefits
Splitting reducers will have and advantage of loading only required part of web application which in turn makes it very efficient in
rendering time of main pages
Organization of code
Splitting reducers on page level or component level will give a better code organization instead of just putting all reducers at one
place. Since reducer is loaded only when page/component is loaded will ensure that there are standalone pages which are not
dependent on other parts of the application.
One page/component
One reducer design pattern. Things are better written, read and understood when they are modular. With dynamic reducers, it
becomes possible to achieve it.
SEO
With reducer level code-splitting, reducers can be code split on a split component level which will reduce the loading time of
website thereby increasing SEO rankings.
# 7. REDUX MIDDLEWARE
# Switch directory
cd my-simple-app
# install Redux-Thunk
npm install --save redux react-redux redux-thunk
Example:
We are going to use Redux Thunk to asynchronously fetch the most recently updated repos by username from Github using this
REST URL:
https://api.github.com/users/learning-zone/repos?sort=updated
// actions.js
export const addRepos = repos => ({
type: 'ADD_REPOS',
repos,
})
// reducers.js
export const repos = (state = [], action) => {
switch (action.type) {
case 'ADD_REPOS':
return action.repos
case 'CLEAR_REPOS':
return []
default:
return state
}
}
// store.js
export function configureStore(initialState = {}) {
const store = createStore(reducers, initialState, applyMiddleware(thunk))
return store
}
applyMiddleware(thunk): This tells redux to accept and execute functions as return values. Redux usually only accepts objects like {
type: 'ADD_THINGS', things: ['list', 'of', 'things'] }.
The middleware checks if the action's return value is a function and if it is it will execute the function and inject a callback function
named dispatch. This way you can start an asynchronous task and then use the dispatch callback to return a regular redux object
action some time in the future.
App.js
// App.js
export class App extends Component {
state = { username: 'learning-zone' }
componentDidMount() {
this.updateRepoList(this.state.username)
}
render() {
return (
<div>
<h1>I AM AN ASYNC APP!!!</h1>
<ul>
{this.props.repos.map((repo, index) => (
<li key={index}>
<a href={repo.html_url} target="_blank">
{repo.name}
</a>
</li>
))}
</ul>
</div>
)
}
}
// AppContainer.js
const mapStateToProps = (state, ownProps) => ({ repos: state.repos })
const mapDispatchToProps = { getRepos }
const AppContainer = connect(mapStateToProps, mapDispatchToProps)(App)
index.js
There are three very popular middleware libraries that allow for side effects and asynchronous actions: Redux Thunk Redux
Saga and Redux Promise.
↥
Q. How can I represent "side effects" such as AJAX
calls? Why do we need things like "action creators",
"thunks", and "middleware" to do async behavior?
Any meaningful web app needs to execute complex logic, usually including asynchronous work such as making AJAX requests. That
code is no longer purely a function of its inputs, and the interactions with the outside world are known as "side effects".
Redux is inspired by functional programming, and out of the box, has no place for side effects to be executed. In particular, reducer
functions must always be pure functions of (state, action) => newState. However, Redux's middleware (eg. Redux Thunk, Redux
Saga) makes it possible to intercept dispatched actions and add additional complex behavior around them, including side effects.
↥
Predictable state container for JavaScript apps. Redux helps you write applications that behave consistently, run in different
environments (client, server, and native), and are easy to test. On top of that, it provides a great developer experience, such as live
code editing combined with a time traveling debugger. However, Redux has one, but very significant problem - it doesn't handle
asynchronous operations very well by itself.
RxJS
The Reactive Extensions for JavaScript. RxJS is a library for reactive programming using Observables, to make it easier to compose
asynchronous or callback-based code.
Redux belongs to "State Management Library" category of the tech stack, while RxJS can be primarily classified under "Concurrency
Frameworks".
Redux RxJS
Redux uses the Reactive paradigm because the Store is RxJS also uses the Reactive paradigm, but instead of being an
reactive. The Store observes actions from a distance, and architecture, it gives you basic building blocks, Observables, to
changes itself. accomplish this pattern.
// create our stream as a subject so arbitrary data can be sent on the stream
const action$ = new Subject();
// Initial State
const initState = { name: 'Alex' };
// Redux reducer
const reducer = (state, action) => {
switch(action.type) {
case 'NAME_CHANGED':
return {
...state,
name: action.payload
};
default:
return state;
}
}
// Reduxification
const store$ = action$
.startWith(initState)
.scan(reducer);
Async actions
Let's say we want to do something asynchronous like fetch some information from a rest api all we need to do is send an ajax stream
in place of our action payload and then use one of the lodash style stream operators, flatMap() to squash the results of the
asynchronous operation back onto the action$ stream.
import { isObservable } from './utils';
// Action creator
const actionCreator = (func) => (...args) => {
const action = func.call(null, ...args);
action$.next(action);
if (isObservable(action.payload))
action$.next(action.payload);
return action;
};
// Reducer
export default function reducer(state, action) {
switch (action.type) {
case 'USERS_LOADING':
return {
...state,
isLoading: true
};
case 'USERS_LOADED':
return {
...state,
isLoading: false,
users: action.payload,
};
//...
}
}
// rest of code...
The advantage of swapping the action payload for a stream is so we can send data updates at the start and the end of the async
operation
Redux Thunk is a middleware that lets you call action creators that return a function instead of an action object. That function
receives the store's dispatch method, which is then used to dispatch regular synchronous actions inside the body of the function
once the asynchronous operations have completed.
npm i --save react-redux redux redux-logger redux-saga redux-thunk
Thunk is a function which optionaly takes some parameters and returns another function, it takes dispatch and getState functions
and both of these are supplied by Redux Thunk middleware.
Example:
export { fetchList }
2. Redux Saga:
Redux Saga leverages an ES6 feature called Generators, allowing us to write asynchronous code that looks synchronous, and is very
easy to test. In the saga, we can test our asynchronous flows easily and our actions stay pure. It organized complicated asynchronous
actions easily and make then very readable and the saga has many useful tools to deal with asynchronous actions.
Example:
function *fetchList () {
{
const responseData = yield call(getCharacters)
yield put({type: "GET_LIST", payload: responseData.list})
} catch (error) {
console.log(error.message)
}
}
export { fetchList }
Both Redux Thunk and Redux Saga take care of dealing with side effects. In very simple terms, applied to the most common scenario
(async functions, specifically AJAX calls) Thunk allows Promises" to deal with them, Saga uses Generators. Thunk is simple to use and
Promises are familiar to many developers, Saga/Generators are more powerful but you will need to learn them. When Promises are
just good enough, so is Thunk, when you deal with more complex cases on a regular basis, Saga gives you better tools.
This is the most simple way of doing Ajax calls with Redux. When using Redux Promise, your action creator can return a Promise
inside the Action.
function getUserName(userId) {
return {
type: "SET_USERNAME",
payload: fetch(`/api/personalDetails/${userId}`)
.then(response => response.json())
.then(json => json.userName)
}
}
This middleware automatically dispatches two events when the Ajax call succeeds: SETUSERNAMEPENDING and SETUSERNAMEFULFILLED. If
something fails it dispatches SETUSERNAMEREJECTED.
When to use
This is the standard way of doing Ajax with Redux. When using Redux Thunk, your action creators returns a function that takes one
argument dispatch:
function getUserName(userId) {
return dispatch => {
return fetch(`/api/personalDetails/${userId}`)
.then(response => response.json())
.then(json => dispatch({ type: "SET_USERNAME", userName: json.userName })
}
}
The action creator can call dispatch inside .then to execute it asynchronously. The action creator can call dispatch as many time as it
wants.
When to use
You make many Ajax calls in one action, and need to dispatch many actions
You require full control of the format of your actions
function* getUserName(action) {
{
const user = yield call(fetch, `/api/personalDetails/${userId}`);
yield put({type: "SET_USERNAME_SUCCEEDED", user: user});
} catch (e) {
yield put({type: "SET_USERNAME_FAILED", message: e.message});
}
}
Here, sagas listen to actions which you dispatch as regular synchronous actions. In this case, the saga getUserName is executed when
the action SET_USERNAME is dispatched. The * next to the function means it's a generator and yield is a generator keyword.
When to use
function* fetchUserSaga(action) {
// `call` function accepts rest arguments, which will be passed to `api.fetchUser` function.
// Instructing middleware to call promise, it resolved value will be assigned to `userData` variable
const userData = yield call(api.fetchUser, action.userId)
Suppose we have a UI to fetch some user data from a remote server when a button is clicked.
The Component dispatches a plain Object action to the Store. We'll create a Saga that watches for all USER_FETCH_REQUESTED actions
and triggers an API call to fetch the user data.
// sagas.js
/*
Starts fetchUser on each dispatched `USER_FETCH_REQUESTED` action.
Allows concurrent fetches of user.
*/
function* mySaga() {
yield takeEvery("USER_FETCH_REQUESTED", fetchUser);
}
/*
Alternatively you may use takeLatest.
To run our Saga, we'll have to connect it to the Redux Store using the redux-saga middleware.
// main.js
# 8. REDUX FORMS
Q. Explain Redux form with an example?
This is a simple demonstration of how to connect all the standard HTML form elements to redux-form.
For the most part, it is a matter of wrapping each form control in a <Field> component, specifying which type
of React.DOM component you wish to be rendered.
The Field component will provide your input with onChange, onBlur, onFocus, onDrag, and onDrop props to listen to the events, as well
as a value prop to make each input a controlled component. Notice that the SimpleForm component has no state; in fact, it uses
the functional stateless component syntax.
Example:
// SimpleForm.js
Reference:
https://redux-form.com/6.5.0/examples/syncvalidation/
# 9. REDUX MISCELLANEOUS
Without a decorator
function mapStateToProps(state) {
return { todos: state.todos }
}
function mapDispatchToProps(dispatch) {
return { actions: bindActionCreators(actionCreators, dispatch) }
}
Using a decorator
function mapStateToProps(state) {
return { todos: state.todos }
}
function mapDispatchToProps(dispatch) {
return { actions: bindActionCreators(actionCreators, dispatch) }
}
@connect(mapStateToProps, mapDispatchToProps)
export default class MyApp extends React.Component {
// ...define your main app here
}
When using Redux, state is stored globally in the Redux store. Any component that needs access to a value may subscribe to the
store and gain access to that value. Typically, this is done using container components. This centralizes all data but makes it very
easy for a component to get the state it needs, without surrounding components knowing of its needs.
Q. What is Flux?
Flux is an application design paradigm used as a replacement for the more traditional MVC pattern. Flux is a Javascript architecture
or pattern for UI which runs on a unidirectional data flow and has a centralized dispatcher. It is useful when your project has dynamic
data and you need to keep the data updated in an effective manner. It was created by Facebook, and complements React as view.
Architecture
Store/ Stores: Serves as a container for the app state & logic
Action: Enables data passing to the dispatcher
View: Same as the view in MVC architecture, but in the context of React components
Dispatcher: Coordinates actions & updates to stores
In the Flux architecture, when a user clicks on something, the view creates actions. Action can create new data and send it to the
dispatcher. The dispatcher then dispatches the action result to the appropriate store. The store updates the state based on the result
and sends an update to the view.
Flux Redux
Ensures simple debugging with the dispatcher Single store makes debugging lot easier
MVC stands for Model View Controller. It is an architectural pattern used for developing the user interface. It divides the application
into three different logical components: the Model, the View, and the Controller.
MVC can be interpreted or modified in many ways to fit a particular framework or library. The core ideas of MVC can be formulated
as:
Separating the presentation from the model: enables implementation of different UIs and better testability
Separating the controller from the view: most useful with web interfaces and not commonly used in most GUI frameworks
In general, MVC makes no assumptions about whether data flow within an application should be unidirectional or bidirectional. In
server Side, MVC is good, but in Client side most of the JS frameworks provide data binding support which let the view can talk with
model directly, It shoudn't be, Many times it become hard to debug something as there are scope for a property being changed by
many ways.
2. Flux
Flux places unidirectional data flow front and center, by making it a requirement. Here are the four major roles that make up the Flux
architecture:
Actions, which are helper methods that relay information to the dispatcher
Stores are similar to the models in MVC, except they act as containers for application state and logic for a particular
domain within the application
The Dispatcher receives Actions and acts as the sole regis of callbacks to all stores within an application. It also manages
the dependencies between stores
Views are the same as the view in MVC, except in the context of React and Flux, and also include Controller-Views for
change events and retrieve application state from stores as required.
1. All data in the application flow through a central hub called the Dispatcher
2. This data is tracked as actions, which are provided to the dispatcher in an action creator method, often as a result of a user
interacting with the view
3. The dispatcher invokes the registered callback, effectively dispatching the action to all stores that have registered with that
callback
4. The stores in turn relay that change event to the controller-views to alert them of the change
5. The controller-views listen for events, retrieve data from the appropriate stores as required and re-render themselves and
all their children in the component tree accordingly.
MVC Flux
Data binding is the key Events or actions are the main players
store.dispatch({
type: 'ADD_TODO',
text: 'Understand the middleware'
})
// (These lines will be logged by the middleware:)
// will dispatch: { type: 'ADD_TODO', text: 'Understand the middleware' }
// state after dispatch: [ 'Use Redux', 'Understand the middleware' ]
In Redux, all application state is held in the store; which is an object that holds the complete state tree of your app. There is only one
way to change its state and that is by dispatching actions.
Actions are objects that consist of a type and a payload property. They are created and dispatched by special functions called action
creators.
When a store is created, Redux dispatches a dummy action to your reducer to populate the store with the initial state.
2. createStore Pattern
The createStore method can accept an optional preloadedState value as its second argument. In our example, we
called createStore() without passing this value. When a value is passed to the preloadedState it becomes the initial state.
const initialState = ["eat", "code", "sleep"];
const store = createStore(todosReducer, initialState)
3. Reducer Pattern
Reducers can also specify an initial state value by looking for an incoming state argument that is undefined, and returning the value
they'd like to use as a default.
In general, preloadedState wins over the state specified by the reducer. This lets reducers specify initial data that makes sense to
them as default arguments, but also allows loading existing data (fully or partially) when you're hydrating the store from some
persistent storage or the server.
↥
Example: Constants in Redux can be used into two places, reducers and during actions creation.
// actionTypes.js
// actions.js
It allows to easily find all usages of that constant across the project. It also prevents from introducing silly bugs caused by typos -- in
which case, you will get a ReferenceError immediately.
↥
Context provides a way to pass data through the component tree without having to pass props down manually at every level.
In a typical React application, data is passed top-down (parent to child) via props, but this can be cumbersome for certain types of
props (e.g. locale preference, UI theme) that are required by many components within an application. Context provides a way to
share values like these between components without having to explicitly pass a prop through every level of the tree.
Redux:
Redux is a pattern and library for managing and updating application state, using events called "actions". It serves as a centralized
store for state that needs to be used across your entire application, with rules ensuring that the state can only be updated in a
predictable fashion.
Redux helps you manage "global" state - state that is needed across many parts of your application.
The patterns and tools provided by Redux make it easier to understand when, where, why, and how the state in your application is
being updated, and how your application logic will behave when those changes occur.
Redux vs Context API
1.) Implementation
Context API is easy to is use as it has a short learning curve. It requires less code, and because there's no need of extra libraries,
bundle sizes are reduced. Redux on the other hand requires adding more libraries to the application bundle. The syntax is complex
and extensive creating unnecessary work and complexity. However, it's still a great alternative regarding prop drilling.
2.) Rendering
Context API prompts a re-render on each update of the state and re-renders all components regardless. Redux however, only re-
renders the updated components.
/**
* In order to reset all reducers back to their initial states when user logout,
* rewrite rootReducer to assign 'undefined' to state when logout
*
* If state passed to reducer is 'undefined', then the next state reducer returns
* will be its initial state instead; since we have assigned it as the default value
* of reducer's state parameter
* ex: const Reducer = (state = InitialState, action) => { ... }
*
* See: https://goo.gl/GSJ98M and combineReducers() source codes for details
*/
Relay achieves this by combining declarative data fetching and a static build step. With declarative data fetching, components
declare what data they need, and Relay figures out how to efficiently fetch it. During the static build step, Relay validates and
optimizes queries, and pre-computes artifacts to achieve faster runtime performance.
Reference:
https://relay.dev/docs/
Predictable state container for JavaScript apps. Redux helps you write applications that behave consistently, run in different
environments (client, server, and native). In redux the application state is located in a single store, each component can access the
state, and can also change the state by dispatching actions. Redux doesn't handle data fetching out of the box, though it can be
done manually: simply create an action that fetches the data from the server into the store.
Predictable state
Easy testing
Works with other view layers besides React
Relay
Created by facebook for react, and also used internally there. Relay is similar to redux in that they both use a single store. The main
difference is that relay only manages state originated from the server, and all access to the state is used via GraphQL querys (for
reading data) and mutations (for changing data). Relay caches the data for you and optimizes data fetching for you, by fetching only
changed data and nothing more. Relay also supports optimistic updates, i.e. changing the state before the server's result arrives.
GraphQL is a web service framework and protocol using declarative and composable queries, and solves problem like over fetching
and under fetching, it is believed to be a valid candidate to replace REST.
1. actionCreators (Function or Object): An action creator, or an object whose values are action creators.
2. dispatch (Function): A dispatch function available on the Store instance.
Returns
(Function or Object): An object mimicking the original object, but with each function immediately dispatching the action returned by
the corresponding action creator. If you passed a function as actionCreators, the return value will also be a single function.
Example:
// TodoActionCreators.js
// TodoListContainer.js
console.log(TodoActionCreators)
// {
// addTodo: Function,
// removeTodo: Function
// }
componentDidMount() {
// Injected by react-redux:
let { dispatch } = this.props
render() {
// Injected by react-redux:
let { todos } = this.props
In React, MapStatetoProps pulls in the state of a specific reducer state object from global store and maps it to the props of
component. MapStateToProps is called everytime your store is updated. You pass in your state a retrieve that specific objects from
the reducer.
2. Using MapDisptachToProps
MapDispatchToProp takes the dispatch functions in component and executes them against the Redux Reducer when that function is
fired. MapDispatchToProps allows to dispatch state changes to your store.
In a simple term,
Example:
function mapStateToProps(state) {
return state
}
// State changer UI
var StateChangerUI = React.createClass({
// Action Dispatch
handleClick: function() {
store.dispatch({
type: 'REVERSE'
})
},
render: function() {
return (
<button type="button" className="btn btn-success" onClick={this.handleClick}>REVERSE</button>
)
}
})
PresentationalComponent = connect(mapStateToProps)(PresentationalComponent)
ReactDOM.render(
<Provider store={store}>
<PresentationalComponent />
</Provider>,
document.getElementById('App')
)
// shorthand way
const mapDispatchToProps = { action }
It should take a first argument called state, optionally a second argument called ownProps, and return a plain object containing the
data that the connected component needs.
This function should be passed as the first argument to connect, and will be called every time when the Redux store state changes. If
you do not wish to subscribe to the store, pass null or undefined to connect in place of mapStateToProps.
Arguments
state
ownProps (optional)
State:
The first argument to a mapStateToProps function is the entire Redux store state.
Example:
// Employee.js
function mapStateToProps(state) {
const { emp } = state
return { empList: emp.allIds }
}
ownProps (optional):
If your component needs the data from its own props to retrieve data from the store. This argument will contain all of the props
given to the wrapper component that was generated by connect.
Example:
// Employee.js
selectors
In our context, selectors are nothing but functions which can compute or retrive data from the store. We usually fetch the state data
using mapStateToProps() function like this.
const mapStateToProps = (state) => {
return {
activeData: getActiveData(state.someData, state.isActive)
}
}
Where getActiveData() will be a function which returns all the records from someData having the status as isActive. The drawback
with this function is, whenever any part of the state state updates, this function will recalculate this data.
When we use Reselect it caches the input arguments to the memoized function. So only when the arguments of the function
changes from the previous call, the selector recalculates.
Example:
// todo.reducer.js
// ...
import { createSelector } from 'reselect';
const todoSelector = state => state.todo.todos;
const searchTermSelector = state => state.todo.searchTerm;
// ...
We can use the filteredTodos selectors to get all the todos if there's no searchTerm set in the state, or a filtered list otherwise.
↥
The dispatch method is a method of the store object. An action is dispatched to trigger an update to the store.
// App.js
import { createStore } from 'redux';
import { MessageSender } from './MessageSender';
import reducer from './reducer';
// MessageSender.js
import { sendMsg } from './actions';
// ...
this.props.store.dispatch(sendMsg(msg))
// ...
The downside of the above approach is that our React component is aware of the app logic. It's best to separate the logic in our
smart component connected to the store from the user interface, i.e., from the dumb component.
From the official docs for connect(), we can describe mapDispatchToProps() this way: If an object is passed, each function inside it is
assumed to be a Redux action creator. An object with the same function names, but with every action creator wrapped into a
dispatch call so they may be invoked directly, will be merged into the component's props.
// MessageSender.container.js
const mapDispatchToProps = {
sendMsg
};
// MessageSender.js
// ...
this.props.sendMsg(msg);
// ...
render() {
return <MsgSending {...this.boundedActions} />;
}
}
Selectors help to keep your Redux store state minimal and derive data from the state as needed. They can compute derived data,
allowing Redux to store the minimal possible state. Selectors are also very efficient. A selector is not recomputed unless one of its
arguments changes.
Example:
Reselect keeps a copy of the last inputs/outputs of the last call, and recomputes the result only if one of the inputs changes. If the
the same inputs are provided twice in a row, Reselect returns the cached output. It's memoization and cache are fully customizable.
↥
Q. Can I dispatch an action in reducer?
Dispatching an action within a reducer is an anti-pattern. Your reducer should be without side effects, simply digesting the action
payload and returning a new state object. Adding listeners and dispatching actions within the reducer can lead to chained actions
and other side effects.
Reference:
https://github.com/reduxjs/redux-devtools
Q. How to set conditional action on state in React-
redux
Actions are plain objects that send data or payloads of information from your component to the global store object.
Consider that the authentication is already in progress, in which case you do not want to dispatch the AUTHENTICATE action. So here,
you need to connect the component to the global store and retrieve the authentication status. You can do that by passing
the mapStateToProps argument to the connect() method. The condition will ensure that the AUTHENTICATE action is dispatched only
when the isAuthentication state is set to false.
import React from "react";
import { connect } from "react-redux";
this.handleFormSubmit = this.handleFormSubmit.bind(this);
}
handleFormSubmit(values) {
if (!this.props.isAuthenticating)
this.props.dispatch({
type: AUTHENTICATE,
payload: values,
});
}
render() {
return (
<div>
<LoginForm onSubmit={this.handleFormSubmit} />
</div>
);
}
}