Download as pdf or txt
Download as pdf or txt
You are on page 1of 21

Unit-3: Forms and Hooks in React.

JS

3.1 Forms: (Adding forms, Handling forms, Submitting


forms)
• Forms are an integral part of any modern web application.
• It allows the users to interact with the application as well as gather
information from the users.
• Forms can perform many tasks that depend on the nature of your
business requirements and logic such as authentication of the user,
adding user, searching, filtering, booking, ordering, etc.
• A form can contain text fields, buttons, checkbox, radio button, etc.
Creating Form
• React offers a stateful, reactive approach to build a form. The component
rather than the DOM usually handles the React form. In React, the form
is usually implemented by using controlled components.
• There are mainly two types of form input in React.
1. Uncontrolled component
• The uncontrolled input is similar to the traditional HTML form
inputs.
• The DOM itself handles the form data. Here, the HTML elements
maintain their own state that will be updated when the input
value changes.
• To write an uncontrolled component, you need to use a ref to get
form values from the DOM.
• In other words, there is no need to write an event handler for
every state update. You can use a ref to access the input field value
of the form from the DOM.

import React, { Component } from 'react';


class App extends React.Component {
constructor(props) {
super(props);
this.updateSubmit = this.updateSubmit.bind(this);
this.input = React.createRef();
}
updateSubmit(event) {
alert('You have entered the UserName and CompanyName s
uccessfully.');
Unit-3: Forms and Hooks in React.JS
event.preventDefault();
}
render() {
return (
<form onSubmit={this.updateSubmit}>
<h1>Uncontrolled Form Example</h1>
<label>Name:
<input type="text" ref={this.input} />
</label>
<label>
CompanyName:
<input type="text" ref={this.input} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
export default App;

2. Controlled component
• In HTML, form elements typically maintain their own state and
update it according to the user input.
• In the controlled component, the input form element is handled
by the component rather than the DOM.
• Here, the mutable state is kept in the state property and will be
updated only with setState() method.
• Controlled components have functions that govern the data
passing into them on every onChange event, rather than grabbing
the data only once, e.g., when you click a submit button. This data
is then saved to state and updated with setState() method. This
makes component have better control over the form elements
and data.
• A controlled component takes its current value through props and
notifies the changes through callbacks like an onChange event.
Unit-3: Forms and Hooks in React.JS
• A parent component "controls" these changes by handling the
callback and managing its own state and then passing the new
values as props to the controlled component. It is also called as a
"dumb component."
import React, { Component } from 'react';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('You have submitted the input successfully: ' + this.state.val
ue);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<h1>Controlled Form Example</h1>
<label>
Name:
<input type="text" value={this.state.value} onChange={th
is.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
export default App;
Unit-3: Forms and Hooks in React.JS

SN Controlled Uncontrolled

1. It does not maintain its internal state. It maintains its internal states.

2. Here, data is controlled by the parent Here, data is controlled by the DOM itself.
component.

3. It accepts its current value as a prop. It uses a ref for their current values.

4. It allows validation control. It does not allow validation control.

5. It has better control over the form elements It has limited control over the form elements
and data. and data.

3.1.1 event.target.name and event.target.event, React


Memo
• event.target returns the DOM element that triggered an specific event,
so we can retrieve any property/ attribute that has a value.
• For example, when we console.log(e.target), we can see the class name
of the element, type, position of the mouse, etc.
• We can access the value of an event with event.target.value.
React Memo
• React Memo is a Higher Order Component (HOC) which itself wraps
around a component to memorize the rendered output and skips
unnecessary renderings.
• The component around which it’s used will generate a memorized or an
optimal version of it to speed up the render process.
• Improve the overall stability and rendering performance of your React
application.
• Allows the component to check the old props against new ones to see if
the value has changed or not.
• Useful when you expect the same result from a component:
you should wrap a component in your React app to React Memo when
you know beforehand that it will render the same result to the DOM when
given the same props to it. Thereby, it will result in a performance boost
as it will memorize the result.
• Only checks for prop changes: this means that if the props are passed
down to the component changes, then only a new render will occur. If the
props remain the same, you will always get the memorized result.
Unit-3: Forms and Hooks in React.JS
Where to use React Memo?
• Use it if you are using a pure functional component: this means that your
component is not using classes and given the same props, it always
renders the same output.
• Use it when you know beforehand that a component will render quite
often.
• Use it if the re-rendering is done using the same props given to the
component. If by any chance the props change, then it’s not a right idea
to use memorization here.
• Use it if your component is big enough to have props equality
check done by React with a decent number of UI elements.
Where NOT to use React Memo?
• Don’t use React Memo if the component isn’t heavy and renders with
different props altogether.
• Wrapping a class-based component in React Memo is undesirable and
therefore should not be used.
import React from "react";
const App = () => {
const [todo, setTodo] = React.useState([
{ title: "Shop groceries 🛒" },
{ title: "Do yoga 🧘" }
]);

const [text, setText] = React.useState("");


const handleText = (e) => { setText(e.target.value); };
const handleAddTodo = () => {
setTodo(todo.concat({ title: text }));
};
return (
<div>
<input type="text" value={text} onChange={handleText} />
<button type="button" onClick={handleAddTodo}>
<span role="img" aria-label="add emojie">

</span>
Add todo
</button>
<Todo list={todo} />
</div>
);
Unit-3: Forms and Hooks in React.JS
};

const Todo = React.memo(({ list }) => {


return (
<ul>
{list.map((item) => (
<TodoItem item={item} />
))}
</ul>
);
});
const TodoItem = React.memo(({ item }) => {
return <li>{item.title}</li>;
});
export default App;
Unit-3: Forms and Hooks in React.JS

3.1.2 Components (TextArea, Drop down list (SELECT))


TextArea
• A great advantage of using <textarea> is that it provides multi-line input
values so that all values can be completely visible to the user.
• Most of the time, <textarea> can be used to add the user’s primary and
secondary addresses so that they can be completely visible to the user.
import React, { Component } from "react";
class Textareademo extends Component {
constructor() {
super();
this.state = { textAreaValue: "" };
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState({ textAreaValue: event.target.value });
}
render() {
return (
<div>
<label>Enter value: </label>
<textarea
value={this.state.textAreaValue}
onChange={this.handleChange}
/>
</div>
);
}
}
export default Textareademo;
Drop down list (Select)
import * as React from 'react';
const DropDown = () => {
const options = [
{ label: 'Fruit', value: 'fruit' },
{ label: 'Vegetable', value: 'vegetable' },
{ label: 'Meat', value: 'meat' },
];
const [value, setValue] = React.useState('fruit');
Unit-3: Forms and Hooks in React.JS
const handleChange = (event) => { setValue(event.target.value);
};
return (
<div>
<Dropdown label="What do we eat?"
options={options}
value={value} onChange={handleChange}
/>
<p>We eat {value}!</p>
</div>
); };
const Dropdown = ({ label, value, options, onChange }) => {
return (
<label>
{label}
<select value={value} onChange={onChange}>
{options.map((option) => (
<option value={option.value}>{option.label}</option>
))}
</select>
</label>
); };
export default DropDown;

3.2 Hooks: Concepts and Advantages


• Hooks are the new feature introduced in the React 16.8 version.
• It allows you to use state and other React features without writing a class.
• Hooks are the functions which "hook into" React state and lifecycle
features from function components.
• It does not work inside classes.
• Hooks are backward-compatible, which means it does not contain any
breaking changes.
When to use a Hooks
If you write a function component, and then you want to add some state to
it, previously you do this by converting it to a class. But now you can do it by
using a Hook inside the existing function component.
Rules of Hooks
Unit-3: Forms and Hooks in React.JS
1. Only call Hooks at the top level
Do not call Hooks inside loops, conditions, or nested functions. Hooks should
always be used at the top level of the React functions. This rule ensures that
Hooks are called in the same order each time a component render.
2. Only call Hooks from React functions
You cannot call Hooks from regular JavaScript functions. Instead, you can call
Hooks from React function components. Hooks can also be called from custom
Hooks.
React Hooks Installation
1. $ npm install react@16.8.0-alpha.1 --save
2. $ npm install react-dom@16.8.0-alpha.1 --save
Hooks State
Hook state is the new way of declaring a state in React app. Hook uses useState()
functional component for setting and retrieving state.
3.2.1 useState, useEffect, useContext
useState
• The React useState Hook allows us to track state in a function component.
• State generally refers to data or properties that need to be tracking in an
application.
• At the top of your component, import the useState Hook.
import { useState } from "react";
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.
import { useState } from "react";

function FavoriteColor() {
const [color, setColor] = useState("");
}

The first value, color, is our current state.


The second value, setColor, is the function that is used to update our state.

Read State

import { useState } from "react";


import ReactDOM from "react-dom/client";

function FavoriteColor() {
Unit-3: Forms and Hooks in React.JS
const [color, setColor] = useState("red");

return <h1>My favorite color is {color}!</h1>


}

const root = ReactDOM.createRoot(document.getElementById('root'));


root.render(<FavoriteColor />);

Update State
import { useState } from "react";
import ReactDOM from "react-dom/client";
function FavoriteColor() {
const [color, setColor] = useState("red");

return (
<>
<h1>My favorite color is {color}!</h1>
<button
type="button"
onClick={() => setColor("blue")}
>Blue</button>
</>
)
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<FavoriteColor />);

What Can State Hold


import { useState } from "react";
import ReactDOM from "react-dom/client";

function Car() {
const [brand, setBrand] = useState("Ford");
const [model, setModel] = useState("Mustang");
const [year, setYear] = useState("1964");
const [color, setColor] = useState("red");

return (
<>
<h1>My {brand}</h1>
<p>
It is a {color} {model} from {year}.
</p>
</>
)
}

const root = ReactDOM.createRoot(document.getElementById('root'));


root.render(<Car />);
Unit-3: Forms and Hooks in React.JS

import { useState } from "react";


import ReactDOM from "react-dom/client";

function Car() {
const [car, setCar] = useState({
brand: "Ford",
model: "Mustang",
year: "1964",
color: "red"
});

return (
<>
<h1>My {car.brand}</h1>
<p>
It is a {car.color} {car.model} from {car.year}.
</p>
</>
)
}

const root = ReactDOM.createRoot(document.getElementById('root'));


root.render(<Car />);

useEffect
• The useEffect Hook allows you to perform side effects in your
components.
• Some examples of side effects are: fetching data, directly updating the
DOM, and timers.
• useEffect accepts two arguments. The second argument is optional.
useEffect(<function>, <dependency>)
import { useState, useEffect } from "react";
import ReactDOM from "react-dom/client";

function Timer() {
const [count, setCount] = useState(0);

useEffect(() => {
setTimeout(() => {
setCount((count) => count + 1);
}, 1000);
});
Unit-3: Forms and Hooks in React.JS
return <h1>I've rendered {count} times!</h1>;
}

const root = ReactDOM.createRoot(document.getElementById('root'));


root.render(<Timer />);

• useEffect runs on every render. That means that when the count changes,
a render happens, which then triggers another effect.
• We should always include the second parameter which accepts an array.
We can optionally pass dependencies to useEffect in this array.

No dependency passed
useEffect(() => {
//Runs on every render
});

An empty array
useEffect(() => {
//Runs only on the first render
}, []);

Props or state values


useEffect(() => {
//Runs on the first render
//And any time any dependency value changes
}, [prop, state]);

import { useState, useEffect } from "react";


import ReactDOM from "react-dom/client";

function Counter() {
const [count, setCount] = useState(0);
const [calculation, setCalculation] = useState(0);

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>
</>
);
}
Unit-3: Forms and Hooks in React.JS
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Counter />);

Effect Cleanup
• Some effects require cleanup to reduce memory leaks.
• Timeouts, subscriptions, event listeners, and other effects that are no
longer needed should be disposed.
• A return function at the end of the useEffect Hook.
import { useState, useEffect } from "react";
import ReactDOM from "react-dom/client";

function Timer() {
const [count, setCount] = useState(0);

useEffect(() => {
let timer = setTimeout(() => {
setCount((count) => count + 1);
}, 1000);

return () => clearTimeout(timer)


}, []);

return <h1>I've rendered {count} times!</h1>;


}

const root = ReactDOM.createRoot(document.getElementById('root'));


root.render(<Timer />);

useContext
• To set the global data and this data can now be accessed in any of the
children’s components without the need to pass it through every parent
Component.
• Syntax
const authContext = useContext(initialValue);
The use Context 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 memoization.
AuthContext.js
import React from 'react';

const authContext = React.createContext({


auth: null,
login: () => {},
Unit-3: Forms and Hooks in React.JS
logout: () => {},
});
export default authContext;
App.jsx
import React, { useState } from 'react';
import LogIn from './Login';
import LogOut from './Logout';
import AuthContext from './AuthContext';

const App = () => {


const [auth, setAuth] = useState(false);
const login = () => {
setAuth(true);
};
const logout = () => {
setAuth(false);
};
return (
<React.Fragment>
<AuthContext.Provider
value={{ auth: auth, login: login}}
>
<p>{auth ? 'Hi! You are Logged In' : 'Oope! Kindly Login'}</p>
<LogIn />
</AuthContext.Provider>
</React.Fragment>
);
};
export default App;
Login.js
import React, { useContext } from 'react';
import AuthContext from './AuthContext';

const Login = () => {


const auth = useContext(AuthContext);
return (
<>
<button onClick={auth.login}>Login</button>
</>
);
Unit-3: Forms and Hooks in React.JS
};
export default Login;

3.2.2 useRef, useReducer, useCallback, useMemo


useRef
• The useRef Hook allows you to persist values between renders.
• It can be used to store a mutable value that does not cause a re-render
when updated.
• It can be used to access a DOM element directly.
• If we tried to count how many times our application renders using
the useState Hook, we would be caught in an infinite loop since this Hook
itself causes a re-render.
To avoid this, we can use the useRef Hook.

import { useState, useEffect, useRef } from "react";


import ReactDOM from "react-dom/client";

function App() {
const [inputValue, setInputValue] = useState("");
const count = useRef(0);

useEffect(() => {
count.current = count.current + 1;
});

return (
<>
<input
type="text"
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
/>
<h1>Render Count: {count.current}</h1>
</>
);
}

const root =
ReactDOM.createRoot(document.getElementById('root'));
Unit-3: Forms and Hooks in React.JS
root.render(<App />);

• useRef() only returns one item. It returns an Object called current.


• When we initialize useRef we set the initial value: useRef(0).

Accessing DOM Elements


import { useRef } from "react";
import ReactDOM from "react-dom/client";

function App() {
const inputElement = useRef();

const focusInput = () => {


inputElement.current.focus();
};

return (
<>
<input type="text" ref={inputElement} />
<button onClick={focusInput}>Focus Input</button>
</>
);
}

const root = ReactDOM.createRoot(document.getElementById('root'));


root.render(<App />);

useReducer

• The useReducer Hook is similar to the useState Hook.


• It allows for custom state logic.
• If you find yourself keeping track of multiple pieces of state that rely on
complex logic, useReducer may be useful.
Syntax

• The useReducer Hook accepts two arguments.

useReducer(<reducer>, <initialState>)

• The reducer function contains your custom state logic and the initial State
can be a simple value but generally will contain an object.
Unit-3: Forms and Hooks in React.JS
• The useReducer Hook returns the current state and a dispatch method.

import { useReducer } from "react";


import ReactDOM from "react-dom/client";

const initialTodos = [
{
id: 1,
title: "Todo 1",
complete: false,
},
{
id: 2,
title: "Todo 2",
complete: false,
},
];

const reducer = (state, action) => {


switch (action.type) {
case "COMPLETE":
return state.map((todo) => {
if (todo.id === action.id) {
return { ...todo, complete: !todo.complete };
} else {
return todo;
}
});
default:
return state;
}
};

function Todos() {
const [todos, dispatch] = useReducer(reducer, initialTodos);

const handleComplete = (todo) => {


dispatch({ type: "COMPLETE", id: todo.id });
};

return (
<>
{todos.map((todo) => (
<div key={todo.id}>
<label>
<input
type="checkbox"
checked={todo.complete}
onChange={() => handleComplete(todo)}
/>
{todo.title}
Unit-3: Forms and Hooks in React.JS
</label>
</div>
))}
</>
);
}

const root = ReactDOM.createRoot(document.getElementById('root'));


root.render(<Todos />);

useCallback
• The React useCallback Hook returns a memoized callback function.
• This allows us to isolate resource intensive functions so that they will not
automatically run on every render.
• The useCallback Hook only runs when one of its dependencies update.
• This can improve performance.
• One reason to use useCallback is to prevent a component from re-
rendering unless its props have changed.

index.js

import { useState } from "react";


import ReactDOM from "react-dom/client";
import Todos from "./Todos";

const App = () => {


const [count, setCount] = useState(0);
const [todos, setTodos] = useState([]);

const increment = () => {


setCount((c) => c + 1);
};
const addTodo = () => {
setTodos((t) => [...t, "New Todo"]);
};

return (
<>
<Todos todos={todos} addTodo={addTodo} />
<hr />
Unit-3: Forms and Hooks in React.JS
<div>
Count: {count}
<button onClick={increment}>+</button>
</div>
</>
);
};

const root = ReactDOM.createRoot(document.getElementById('root'));


root.render(<App />);

Todos.js
import { memo } from "react";

const Todos = ({ todos, addTodo }) => {


console.log("child render");
return (
<>
<h2>My Todos</h2>
{todos.map((todo, index) => {
return <p key={index}>{todo}</p>;
})}
<button onClick={addTodo}>Add Todo</button>
</>
);
};

export default memo(Todos);

useMemo
• The React useMemo Hook returns a memorized value.
• The useMemo Hook only runs when one of its dependencies update.
• This can improve performance.
• The useMemo Hook can be used to keep expensive, resource intensive
functions from needlessly running.

import { useState, useMemo } from "react";


import ReactDOM from "react-dom/client";

const App = () => {


Unit-3: Forms and Hooks in React.JS
const [count, setCount] = useState(0);
const [todos, setTodos] = useState([]);
const calculation = useMemo(() => expensiveCalculation(count), [count]);

const increment = () => {


setCount((c) => c + 1);
};
const addTodo = () => {
setTodos((t) => [...t, "New Todo"]);
};

return (
<div>
<div>
<h2>My Todos</h2>
{todos.map((todo, index) => {
return <p key={index}>{todo}</p>;
})}
<button onClick={addTodo}>Add Todo</button>
</div>
<hr />
<div>
Count: {count}
<button onClick={increment}>+</button>
<h2>Expensive Calculation</h2>
{calculation}
</div>
</div>
);
};

const expensiveCalculation = (num) => {


console.log("Calculating...");
for (let i = 0; i < 1000000000; i++) {
num += 1;
}
return num;
};

const root = ReactDOM.createRoot(document.getElementById('root'));


Unit-3: Forms and Hooks in React.JS
root.render(<App />);

3.2.3 Hook: Building custom hook, advantages and use

• React.Js provides lots of built-in hooks that you can use in your React
apps.
• You can make your own custom hooks and use it in your apps resulting
in better readability and a reduced amount of code.
• Custom hooks are normal JavaScript functions whose names start with
“use” and they may call other hooks(built-in or custom).
Custom hooks give us following benefits:

• Completely separate logic from user interface.


• Reusable in many different components with the same processing logic.
Therefore, the logic only needs to be fixed in one place if it changes.
• Share logic between components.
• Hide code with complex logic in a component, make the component
easier to read.

When to use React custom hook?

• When a piece of code (logic) is reused in many places (it’s easy to see
when you copy a whole piece of code without editing anything, except
for the parameter passed. Split like how you separate a function).
• When the logic is too long and complicated, you want to write it in
another file, so that your component is shorter and easier to read
because you don’t need to care about the logic of that hook anymore.

Building a custom hook:

You might also like