Advance React
Module 6
Advance React
React Hooks
React Hooks are in-built functions that allow React
developers to use state and lifecycle methods inside
functional components, they also work together with existing
code, so they can easily be adopted into a codebase. The way
Hooks were pitched to the public was that they allow
developers to use state in functional components but under
the hood, Hooks are much more powerful than that. They
allow React Developers to enjoy the following benefits:
Improved code reuse;
Better code composition;
Better defaults;
Sharing non-visual logic with the use of custom hooks;
Flexibility in moving up and down the components tree.
Advance React
There are two main rules that are strictly to be adhered to as
stated by the React core team in which they outlined in the
hooks proposal documentation.
Make sure to not use Hooks inside loops, conditions, or
nested functions;
Only use Hooks from inside React Functions.
Advance React
Basic React Hooks #
There are 10 in-built hooks that was shipped with React 16.8
but the basic (commonly used) hooks include:
useState()
useEffect()
useContext()
useReducer()
useRef()
refer this article for further details about useState() and
useEffect()
https://www.smashingmagazine.com/2020/04/react-hooks-api-
guide/
Advance React
React Refs
Refs is the shorthand used for references in React.
Refs are a function provided by React to access the
DOM element and the React element that you
might have created on your own. They are used in
cases where we want to change the value of a child
component, without making use of props and all.
They also provide us with good functionality as we
can use callbacks with them.
Advance React
Think of refs as a direct connection between
components and DOM elements or class
components and their parent components. This
connection provides us with the means to access
elements/components without state updates and
rerenders.
you should consider using refs when you need to:
Manage focus, text selection, or media playback.
Perform imperative animations.
Integrate with third-party DOM libraries.
Advance React
Refs are usually defined in the constructor of class
components, or as variables at the top level of
functional components, and then attached to an
element in the render() function. Here is a bare-
bones example where we are creating a ref and
attaching it to an <input> element:
Advance React
class MyComponent extends React.Component {
constructor(props) {
super(props)
this.myRef = React.createRef();
}
...
render() {
return (
<>
<input
name="email"
onChange={this.onChange}
ref={this.myRef}
type="text"
</>
)
}
}
Advance React
Refs are created using React.createRef(), and are assigned to
class properties. In the above example the ref is named
myRef, which is then attached to an <input> DOM element.
Once a ref is attached to an element, that element can then
be accessed and modified through the ref.
Adding a button to the previous example. We can then attach
an onClick handler that will utilise myRef to focus the
<input> element it is attached to:
Advance React
handleClick = () => {
this.myRef.current.focus();
}
render() {
return (
...
<button onClick={this.handleClick}>
Focus Email Input
</button>
</>
)
}
Advance React
By doing this we are in fact changing the state of an input
element without any React state updates. This makes sense in
the case of focussing an <input>— we wouldn’t want to re-
render elements every time we focus / blur an input.
Advance React
UseEffect:
The word effect refers to a functional programming term
called a "side effect".
Side effects are not predictable because they are actions
which are performed with the "outside world."
We perform a side effect when we need to reach outside of
our React components to do something. Performing a side
effect, however, will not give us a predictable result.
Think about if we were to request data (like blog posts) from
a server that has failed and instead of our post data, gives us
a 500 status code response.
Advance React
Virtually all applications rely on side effects to work in one
way or another, aside from the simplest applications.
Common side effects include:
Making a request to an API for data from a backend server
To interact with browser APIs (that is, to use document or
window directly)
Using unpredictable timing functions like setTimeout or
setInterval.
This is why useEffect exists: to provide a way to handle
performing these side effects in what are otherwise pure
React components.
Advance React
For example, if we wanted to change the title meta tag to
display the user's name in their browser tab, we could do it
within the component itself, but we shouldn't.
function User({ name }) {
document.title = name;
// This is a side effect. Don't do this in the component body!
return <h1>{name}</h1>;
}
Advance React
If we perform a side effect directly in our component body, it
gets in the way of our React component's rendering.
Side effects should be separated from the rendering process.
If we need to perform a side effect, it should strictly be done
after our component renders.
This is what useEffect gives us.
In short, useEffect is a tool that lets us interact with the
outside world but not affect the rendering or performance of
the component that it's in.
Advance React
The basic syntax of useEffect is as follows:
// 1. import useEffect
import { useEffect } from 'react';
function MyComponent() {
// 2. call it above the returned JSX
// 3. pass two arguments to it: a function and an array
useEffect(() => {}, []);
// return ...
}
Advance React
The correct way to perform the side effect in our User component is
as follows:
We import useEffect from "react"
We call it above the returned JSX in our component
We pass it two arguments: a function and an array
import { useEffect } from 'react';
function User({ name }) {
useEffect(() => {
document.title = name;
}, [name]);
return <h1>{name}</h1>;
}
Advance React
The function passed to useEffect is a callback function. This will be
called after the component renders.
In this function, we can perform our side effects or multiple side
effects if we want.
The second argument is an array, called the dependencies array. This
array should include all of the values that our side effect relies upon.
In our example above, since we are changing the title based off of a
value in the outer scope, name, we need to include that within the
dependencies array.
Advance React
What this array will do is it will check and see if a value (in this case
name) has changed between renders. If so, it will execute our use
effect function again.
This makes sense because if the name changes, we want to display
that changed name and therefore run our side effect again.
Advance React
React useEffect is a function that gets executed for 3 different React
component lifecycles.
Those lifecycles are componentDidMount, componentDidUpdate, and
componentWillUnmount lifecycles.
Basic usage of useEffect
import React, { useState } from 'react';
const App = () => {
const [message, setMessage] = useState('Hi there, how are you?');
return <h1>{message}</h1>
};
export default App;
Advance React
using React useState to save a message.
grabbing state variable, message, and printing it to the screen.
Advance React
using useEffect to change the message a second after the component
has mounted.
import React, { useState, useEffect } from 'react';
const App = () => {
const [message, setMessage] = useState('Hi there, how are you?');
useEffect(() => {
console.log('trigger use effect hook');
setTimeout(() => {
setMessage("I'm fine, thanks for asking.");
}, 1000)
})
return <h1>{message}</h1>
};
export default App;
Advance React
useEffect has been imported from the React library and we have
added my effect under the useState line.
useEffect accepts a function as it’s first argument. This function
handler will take care of any side effects you like when it gets run.
The function is a callback function after one of the React component
lifecycle has been triggered.
Advance React
MVC is covered in React Module.
Advance React
React Flux
Advance React
If you have started working on ReactJS recently then you might be
wondering how to manage state in React so that your application can
scale.
To solve this state management issue, many companies and people
have developed various solutions. Facebook, who developed ReactJS,
came up with a solution called Flux.
What is flux?
Flux uses a unidirectional data flow pattern to solve state
management complexity. Remember it is not a framework – rather
it's more of a pattern that targets to solve the state management
issue.
Are you wondering what's wrong with the existing MVC framework?
Imagine your client's application scales up. You have interaction
between many models and views. How would it look?
Advance React
Advance React
The relationship between components gets complicated. It becomes
hard to scale the application. Facebook faced the same issue. To
solve this issue they architected a Single directional data flow.
Advance React
As you can see from the image above, there are a lot of components
used in Flux. Let's go through all the components one by one.
View: this component renders the UI. Whenever any user interaction
occurs on it (like an event) then it fires off the action. Also when the
Store informs the View that some change has occurred, it re-renders
itself. For example, if a user clicks the Add button.
Action: this handles all the events. These events are passed by the
view component. This layer is generally used to make API calls. Once
the action is done it is dispatched using the Dispatcher. The action
can be something like add a post, delete a post, or any other user
interaction.
Advance React
The common structure of the payload for dispatching an event is as
follows:
{
actionType: "",
data: {
title: "Understanding Flux step by step",
author: "Sharvin"
}
}
The actionType key is compulsory and it is used by the dispatcher to
pass updates to the related store. It is also a known practice to use
constants to hold the value name for actionType key so no typos
occur. Data holds the event information that we want to dispatch
from Action to Store. The name for this key can be anything.
Advance React
Dispatcher: this is the central hub and singleton registry. It
dispatches the payload from Actions to Store. Also makes sure that
there are no cascading effects when an action is dispatched to the
store. It ensures that no other action happens before the data layer
has completed processing and storing operations.
Consider this component has a traffic controller in the system. It is a
centralized list of callbacks. It invokes the callback and broadcasts
the payload it received from the action.
Due to this component, the data flow is predictable. Every action
updates the specific store with the callback that is registered with
the dispatcher.
Advance React
Store: this holds the app state and is a data layer of this pattern. Do
not consider it as a model from MVC. An application can have one or
many app stores. Stores get updated because they have a callback
that is registered using the dispatcher.
Node's event emitter is used to update the store and broadcast the
update to view. The view never directly updates the application
state. It is updated because of the changes to the store.
Advance React
This is only part of Flux that can update the data. Interfaces
implemented in the store are as follows:
The EventEmitter is extended to inform the view that store data has
been updated.
Listeners like addChangeListener and removeChangeListener are
added.
emitChange is used to emit the change.
Consider the below diagram with more stores and views. Still, the
pattern and the flow of data will be the same. This is because this is
a single direction and predictable data flow, unlike MVC or Two-way
binding. This improves the data consistency and it's easier to find
the bug.
Advance React
Advance React
Well, Flux brings the following key benefits to the table with the help
of unidirectional data flow:
The code becomes quite clear and easy to understand.
Easily testable using Unit Test.
Scalable apps can be built.
Predictable data flow.
Advantage of Flux
It is a unidirectional data flow model which is easy to understand.
It is open source and more of a design pattern than a formal
framework like MVC architecture.
The flux application is easier to maintain.
The flux application parts are decoupled.
Advance React
Bundling the application and Web pack:
The React app bundled their files using tools like Webpack or
Browserfy. Bundling is a process which takes multiple files and
merges them into a single file, which is called a bundle. The bundle
is responsible for loading an entire app at once on the webpage. We
can understand it from the below example.
App.js
import { add } from './math.js';
console.log(add(16, 26)); // 42
math.js
export function add(a, b) {
return a + b;
}
Advance React
Bundle file as like below:
function add(a, b) {
return a + b;
}
console.log(add(16, 26)); // 42
Advance React
As our app grows, our bundle will grow too, especially when we are using
large third-party libraries. If the bundle size gets large, it takes a long time to
load on a webpage. For avoiding the large bundling, it?s good to start ?
splitting? your bundle.
React 16.6.0, released in October 2018, and introduced a way of performing
code splitting. Code-Splitting is a feature supported by Webpack and
Browserify, which can create multiple bundles that can be dynamically loaded
at runtime.
Code splitting uses React.lazy and Suspense tool/library, which helps you to
load a dependency lazily and only load it when needed by the user.
The code splitting improves:
The performance of the app
The impact on memory
The downloaded Kilobytes (or Megabytes) size
Advance React
React.lazy
The best way for code splitting into the app is through the dynamic import()
syntax. The React.lazy function allows us to render a dynamic import as a
regular component.
Before
import ExampleComponent from './ExampleComponent';
function MyComponent() {
return (
<div>
<ExampleComponent />
</div>
);
}
Advance React
After
const ExampleComponent = React.lazy(() => import('./ExampleComponent'));
function MyComponent() {
return (
<div>
<ExampleComponent />
</div>
);
}
The above code snippet automatically loads the bundle which contains the
ExampleComponent when the ExampleComponent gets rendered.
Advance React
Suspense
If the module which contains the ExampleComponent is not yet loaded by the
function component(MyComponent), then we need to show some fallback
content while we are waiting for it to load. We can do this using the suspense
component. In other words, the suspense component is responsible for
handling the output when the lazy component is fetched and rendered.
const ExampleComponent = React.lazy(() => import('./
ExampleComponent'));
function MyComponent() {
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<ExampleComponent />
</Suspense>
</div>
);
}
Advance React
The fallback prop accepts the React elements which you want to render while
waiting for the component to load. We can combine multiple lazy components
with a single Suspense component. It can be seen in the below example.
const ExampleComponent = React.lazy(() => import('./
ExampleComponent'));
const ExamComponent = React.lazy(() => import('./ ExamComponent'));
function MyComponent() {
return (
<div>
<Suspense fallback={<div>Loading...</div>}>
<section>
<ExampleComponent />
<ExamComponent />
</section>
</Suspense>
</div>
);
}
Advance React
Error boundaries
If any module fails to load, for example, due to network failure, we will get an
error. We can handle these errors with Error Boundaries. Once we have
created the Error Boundary, we can use it anywhere above our lazy
components to display an error state.
import MyErrorBoundary from './MyErrorBoundary';
const ExampleComponent = React.lazy(() => import('./ ExampleComponent'));
const ExamComponent = React.lazy(() => import('./ ExamComponent'));
const MyComponent = () => (
<div>
<MyErrorBoundary>
<Suspense fallback={<div>Loading...</div>}>
<section>
<ExampleComponent />
<ExamComponent />
</section>
</Suspense>
</MyErrorBoundary>
</div>
);
Advance React
Route-based code splitting
It is very tricky to decide where we introduce code splitting in the app. For
this, we have to make sure that we choose the place which will split the
bundles evenly without disrupting the user experience.
The route is the best place to start the 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.
Advance React
import { Switch, BrowserRouter as Router, Route} from 'react-router-dom';
import React, { Suspense, lazy } from 'react';
const Home = lazy(() => import('./routes/Home'));
const About = lazy(() => import('./routes/About'));
const Contact = lazy(() => import('./routes/Contact'));
const App = () => (
<Router>
<Suspense fallback={<div>Loading...</div>}>
<Switch>
<Route exact path="/" component={Home}/>
<Route path="/about" component={About}/>
<Route path="/contact" component={Contact}/>
</Switch>
</Suspense>
</Router>
);
Advance React
Named Export
Currently, React.lazy supports default exports only. If any module you want to
import using named exports, you need to create an intermediate module that
re-exports it as the default. We can understand it from the below example.
ExampleComponents.js
export const MyFirstComponent = /* ... */;
export const MySecondComponent = /* ... */;
MyFirstComponent.js
export { MyFirstComponent as default } from "./ExampleComponents.js";
MyApp.js
import React, { lazy } from 'react';
const MyFirstComponent = lazy(() => import("./MyFirstComponent.js"));