Unit-3 (React JS)
Unit-3 (React JS)
Unit-3
Component Constructor
If there is a constructor() function in your component, this function will be called when the
component gets initiated.
The constructor function is also where you have the inheritance of the parent component by
including the super() statement, which executes the parent component's constructor function, and
your component has access to all the functions of the parent component (React.Component).
Example
Create a constructor function in the Car component, and add a color property:
When a value in the state object changes, the component will re-render, meaning that the output
will change according to the new value(s).
Example:
Add a button with an onClick event that will change the color property:
class Car extends React.Component {
constructor(props) {
super(props);
this.state = {
brand: "Ford", model: "Mustang", color: "red", year: 1964
};
}
changeColor = () => {
this.setState({color: "blue"});
}
render() {
return (
<div>
<h1>My {this.state.brand}</h1>
<p>
It is a {this.state.color}
{this.state.model}
from {this.state.year}.
</p>
<button
type="button"
onClick={this.changeColor}
>Change color</button>
</div>
);
}
}export default Car;
Props state
Props get passed to the component State is managed within the component
Function parameters Variables declared in the function body
Props are immutable State can be changed
Props-functional Components this.props – useState Hook-Functional Components
Class Components this.state-Class Components
React Hooks
Simplifying complex scenarios: While creating components for complex scenarios such as
data fetching and subscribing to events it is likely that all related code is not organized in
one place are scattered among different life cycle methods.
For example, actions like data, fetching are usually done
in componentDidMount(The componentDidMount() method is called after the component
is rendered.This is where you run statements that requires that the component is already
placed in the DOM) or componentDidUpdate(The componentDidUpdate method is called
after the component is updated in the DOM.), similarly, in case of event listeners, it is done
in componentDidMount or componentWillUnmount (The componentWillUnmount method
is called when the component is about to be removed from the DOM). These develop a
scenario where completely different codes like data fetching and event listeners end up in
the same code-block. This also makes impossible to brake components to smaller
components because of stateful logic. Hooks solve these problems by rather than forcing a
split based on life-cycle method Hooks to let you split one component into smaller
functions based on what pieces are related.
Hook Rules
3.2.1useState Hook
Import useState
To use the useState Hook, we first need to import it into our component.
Initialize useState
We initialize our state by calling useState in our function component.
useState accepts an initial state and returns two values:
The current state.
A function that updates the state.
function FavoriteColor() {
console.log(firstName);//"alpha"
console.log(secondName);//"beta"
</script>/
Read State
If we only called setCar({color: "blue"}), this would remove the brand, model, and year from our
state.
We can use the JavaScript spread operator to overcome the above example.
Spread Operator
The JavaScript spread operator (...) allows us to quickly copy all or part of an existing array or
object into another array or object.
Example
const numbersOne = [1, 2, 3];
const numbersTwo = [4, 5, 6];
const numbersCombined = [...numbersOne, ...numbersTwo];
Example:
Use the JavaScript spread operator to update only the color of the car:
import { useState } from "react";
function Car() {
const [car, setCar] = useState({
brand: "Ford", model: "Mustang", year: "1964", color: "red"
});
const updateColor = () => {
setCar(previousState => {
return { ...previousState, color: "blue" }
});
}
return (
<>
<h1>My {car.brand}</h1>
<p>
It is a {car.color} {car.model} from {car.year}.
</p>
<button
type="button"
onClick={updateColor}
>Blue</button>
</>
)
}
export default Car;
The useEffect Hook allows you to perform side effects in your components. Commented [Ma2]: Anything that affects something
outside of the scope of the current function that’s being
executed.
Some examples of side effects are: fetching data, directly updating the DOM, and timers.
useEffect(<function>, <dependency>)
Example:
Use setTimeout() to count 1 second after initial render:
import { useState, useEffect } from "react";
function Timer() {
const [count, setCount] = useState(0);
useEffect(() => {
setTimeout(() => {
setCount((count) => count + 1);
}, 1000);
});
useEffect runs on every render. That means that when the count changes, a render happens,
which then triggers another effect.
This is not what we want. There are several ways to control when side effects run.
We should always include the second parameter which accepts an array. We can optionally pass
dependencies to useEffect in this array.
Here is an example of a useEffect Hook that is dependent on a variable. If the count variable
updates, the effect will run again:
useEffect(() => {
setCalculation(() => count * 2);
}, [count]); // <- add the count variable here
return (
<>
<p>Count: {count}</p>
<button onClick={() => setCount((c) => c + 1)}>+</button>
<p>Calculation: {calculation}</p>
</>
)export default Counter;
It can be used together with the useState Hook to share state between deeply nested components
more easily than with useState alone.
The Problem is when State is held by the highest parent component in the stack that requires
access to the state at the lowest child component.
To illustrate, we have many nested components. The component at the top and bottom of the
stack need access to the state.
To do this without Context, we will need to pass the state as "props" through each nested
component. This is called "prop drilling".
Example:
<h1>Component 3</h1>
<Component4 user={user} />
</>
);
}
Solution:
The Solution
Create Context
Next we'll use the Context Provider to wrap the tree of components that need the state Context.
Context Provider
Wrap child components in the Context Provider and supply the state value.
function Component1() {
const [user, setUser] = useState("Jesse Hall");
return (
<UserContext.Provider value={user}>
<h1>{`Hello ${user}!`}</h1>
<Component2 user={user} />
</UserContext.Provider>
);
}
Now, all components in this tree will have access to the user Context.
Full Example:
Here is the full example using React Context:
import { useState, createContext, useContext } from "react";
const UserContext = createContext();
function Component1() {
const [user, setUser] = useState("Jesse Hall");
return (
<UserContext.Provider value={user}>
<h1>{`Hello ${user}!`}</h1>
<Component2 user={user} />
</UserContext.Provider>
);
}
function Component2() {
return (
<>
<h1>Component 2</h1>
<Component3 />
16
</>
);
}
function Component3() {
return (
<>
<h1>Component 3</h1>
<Component4 />
</>
);
}
function Component4() {
return (
<>
<h1>Component 4</h1>
<Component5 />
</>
);
}
function Component5() {
const user = useContext(UserContext);
return (
<>
<h1>Component 5</h1>
<h2>{`Hello ${user} again!`}</h2>
</>
);
}
export default Component1;
useCallback Hook
17
The useCallback hook is used when you have a component in which the child is
rerendering again and again without need.
Pass an inline callback and an array of dependencies. 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.
Syntax:
const memoizedCallback = useCallback(
() => {
doSomething(a, b);
},
[a, b],
);
Without useCallback Hook: The problem is that once the counter is updated, all
three functions are recreated again. The alert increases by three at a time but if we
update some states all the functions related to that states should only re-instantiated.
If another state value is unchanged, it should not be touched. Here, the filename is
App.jsWith useCallback hook: To solve this problem we can use the useCallback
hook. Here, the filename is App.js.
funccount.add(decrementCounter);
funccount.add(incrementNumber);
alert(funccount.size);
return (
<div>
Count: {count}
<button onClick={incrementCounter}> Increase counter </button>
<button onClick={decrementCounter}>Decrease Counter </button>
<button onClick={incrementNumber}>Increase number </button>
</div>
)
}
export default App;
Output: As we can see from the below output when we change the state ‘count’ then
two functions will re-instantiated so the set size will increase by 2 and when we update
the state ‘number’ then only one function will re-instantiated and the size of the set will
increase by only one.
React useMemo Hook
The useMemo is a hook used in the functional component of react that returns a
memoized value. In Computer Science, memoization is a concept used in general
when we don’t need to recompute the function with a given argument for the next time
as it returns the cached result. A memoized function remembers the results of output
for a given set of inputs. For example, if there is a function to add two numbers, and
we give the parameter as 1 and 2 for the first time the function will add these two
numbers and return 3, but if the same inputs come again then we will return the
cached value i.e 3 and not compute with the add function again. In react also, we use
this concept, whenever in the React component, the state and props do not change
the component and the component does not re-render, it shows the same output. The
useMemo hook is used to improve performance in our React application.
Syntax:
const memoizedValue = useMemo(functionThatReturnsValue,
arrayDepencies)
Example:
19
In an example, we can see that even if we changed the input number once, but clicked
on-increment counter multiple times our function squareNum got executed whenever
we clicked the increment counter button multiple times. This is happening because the
App component re-renders whenever we change the state of the counter.
Now let’s solve this problem using the useMemo hook.
When we use useMemo Hook
<div>OUTPUT: {squaredNum}</div>
<button onClick= {counterHander}>Counter ++</button>
20
<div>Counter : {counter}</div>
</div>
);
}
Output: Now in the above example, we have used the user memo hook, here the
function that returns the value i.e squareNum is passed inside the useMemo and
inside the array dependencies, we have used the number as the squareNum will run
only when the number changes. If we increase the counter and the number remains
the same in the input field the squareNum doesn’t run again.
The useReducer Hook is the better alternative to the useState hook and is generally more
preferred over the useState hook when you have complex state-building logic or when the next
state value depends upon its previous value or when the components are needed to be optimized.
The useReducer hook takes three arguments including reducer, initial state, and the function to
load the initial state lazily(Sometimes instead of passing a primitive value, an object or an array
as argument, you can also pass a function. The value returned by the function passed is used for
initializing state.That is referred to as lazy state initialization. Lazy state initialization is
necessary if you are performing a computationally expensive process for initializing state.).
Syntax:
const [state, dispatch] = useReducer(reducer, initialArgs, init);
21
Example: Here reducer is the user-defined function that pairs the current state with the dispatch
method to handle the state, initialArgs refers to the initial arguments and init is the function to
initialize the state lazily.
App.js: Program to demonstrate the use of useReducer Hook:
function App() {
Output: In this example, we have a button called ACTION, whenever we click on the button the
onClickHandler is getting triggered and it’s focusing the textarea with help of useRef hook. The focusPoint
is the useRef object which is initialised to null and the value is changing to onClick event.
24
When you have component logic that needs to be used by multiple components, we
can extract that logic to a custom Hook.
App.jsx
import './App.css';
function App() {
return (
<div className="App">
<Test/>
</div>
);
Text.jsx
25
const [count,setCount]=useState(0);
useTitleCount(count);
console.log("UseEffects Outside");
return (
<div>
<h1>{count}</h1>
</div>
useTitleCount.jxs
26
//useEffect(()=>{console.log("Inside useEffects");
Example:
Add a form that allows users to enter their name: MyForm.jsx
function MyForm() {
return (
<form>
<label>Enter your name:
<input type="text" />
</label>
27
</form>)
}
export default MyForm;
Handling Forms
Handling forms is about how you handle the data when it changes value or gets submitted.
When the data is handled by the components, all the data is stored in the component state.
You can control changes by adding event handlers in the onChange attribute.
We can use the useState Hook to keep track of each inputs value and provide a "single source of
truth" for the entire application.
function Form() {
const [formData, setFormData] = useState({
name:"",
email:""
});
</div>
<div>
<button type="submit" >submit</button>
</div>
</form>
)
}export default Form;
React Memo
Using memo will cause React to skip rendering a component if its props have not changed.
Problem
In this example, the Todos component re-renders even when the todos have not changed.
Example:
App.js:
30
return (
<>
<Todos todos={todos} />
<hr />
<div>
Count: {count}
<button onClick={increment}>+</button>
</div>
</>
);
};
export default App;
Todos.js:
const Todos = ({ todos }) => {
console.log("child render");
return (
<>
31
<h2>My Todos</h2>
{todos.map((todo, index) => {
return <p key={index}>{todo}</p>;
})}
</>
);
};
export default Todos;
When you click the increment button, the Todos component re-renders.
Solution
Example:
index.js:
import { useState } from "react";
import Todos from "./Todos";
return (
<>
<Todos todos={todos} />
<hr />
<div>
Count: {count}
<button onClick={increment}>+</button>
</div>
</>
);
};
export default App;
Todos.js:
import { memo } from "react";
function Myform() {
const [username, setUsername] = useState("");
const [mySubject, setSubject] = useState("React");
const [textarea, setTextarea] = useState(
"Enter the description here"
);
const handleChange = (event) => {
setTextarea(event.target.value)
}
<div>
<label>Username</label>
<input type="text" value={username}
onChange={handleUsernameChange}/>
</div>
<div>
<label>Description</label>
<textarea value={textarea} onChange={handleChange} />
</div>
<div>
<label>Subject</label>
<select value={mySubject} onChange={handleSubjectChange}>
<option value="React">React</option>
<option value="AngularJS">AngularJS</option>
<option value="Vue">Vue</option>
</select>
</div>
<div>
<button type="submit" >submit</button>
</div>
</form>
)
}
35