Introduction
React is a free and open-source front–end javascript library which was created by Facebook and donated as opensource in 2013. React is used for building user interfaces based on UI components. It is maintained by Meta and a community of individual developers and companies.
Reacts are Single Page Applications, wherein DOM/ UI is loaded only once, and next time the page is only updating the data.
React can be used as a base in the development of single-page or mobile applications. However, React is only concerned with state management and rendering that state to the DOM, so creating React applications usually requires the use of additional libraries for routing, as well as certain client-side functionality
React.js does not use a webserver to create virtual DOMs. It builds the virtual DOM and does its diff operations on the client’s browser.
First App
Default App.js
- Create a New Project
- npx create-react-app my-app
- Run the app
- cd my-app
- yarn start
- Your First app is ready
Modify App.js
index.html -> index.js -> App.js ( First page to load is index.html, followed by index.js, and by default configuration invokes App.js)
In React, you can work with JS + HTML together, this is possible using libraries like Babel which converts the JSX syntax to browser compatible JS in the background. For example, Let’s modify the app.js file with the following data
Output
First Component
Step1: In the components, folder create the first Welcome.js component file
const Welcome = () => {
return <h1>this is a first react component</h1>
}
export default Welcome
Use this component in App.js
import './App.css'
import Welcome from './components/Welcome'
function App() {
return <Welcome />
}
export default App
Output
Physical DOM vs Virtual DOM
What is DOM?
When a web page is loaded, the browser creates a Document Object Model of the page. The HTML DOM model is constructed as a tree of Objects:
With the object model, JavaScript gets all the power it needs to create dynamic HTML: i.e JavaScript can change all the HTML elements, CSS styles on the page
Virtual DOM
The virtual DOM (VDOM) is a programming concept where an ideal, or “virtual”, representation of a UI is kept in memory and synced with the “real” DOM by a library such as ReactDOM. This process is called reconciliation.
This approach enables the declarative API of React: You tell React what state you want the UI to be in, and it makes sure the DOM matches that state. This abstracts out the attribute manipulation, event handling, and manual DOM updating that you would otherwise have to use to build your app.
More about Components
Components are Reacts reusable entities.
Component props
Create a Person Component, and use props to take a read-only input and use that in the page.
const Person = (props) => {
console.log(props)
return <div>{props.name}</div>
}
export default Person
In the App.js use pass a value
<Person name="person1" />
Component State
We will apply useState() to add data to components state and return a reference to variable and function. Let’s see an example of its usage in Counter.js
import { useState } from 'react'
const Counter = () => {
const [counter, setCounter] = useState(0)
const onIncrement = () => {
setCounter(counter + 1)
}
return (
<div>
<h3>Counter</h3>
<div>counter: {counter}</div>
<div style={{ marginTop: '20px' }}>
<button onClick={onIncrement}>Increment</button>
</div>
</div>
)
}
export default Counter
Output
React Events
OnChange Event
This is known as Event Binding in Angular and helps to get value immediately as when the user changes it, Let us see an example.
import { useState } from 'react'
const Form = () => {
const [userName, setUserName] = useState('')
const onChangeInput = (e) => {
setUserName(e.target.value)
}
return (
<div>
User name : <input onChange={onChangeInput} />
<div>{userName}</div>
</div>
)
}
export default Form
Output
React + Bootstrap
Add inside index.html the javascript library from https://getbootstrap.com/
<!-- CSS only -->
<link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3"
crossorigin="anonymous"
/>
<!-- JavaScript Bundle with Popper -->
<script
src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"
integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p"
crossorigin="anonymous"
></script>
HTTP Connection + UseEffect Hook + Conditional Rendering
Lets first create component to display a table
const UserTableRow = (props) => {
const { id, email, first_name, last_name, avatar } = props.user
return (
<tr>
<td>
<img style={{ width: '30px', height: '30px' }} src={avatar} />
</td>
<td>{id}</td>
<td>{email}</td>
<td>{first_name}</td>
<td>{last_name}</td>
</tr>
)
}
export default UserTableRow
Add HTTP Connection call
import { useEffect, useState } from 'react'
import UserTableRow from '../components/UserTableRow'
const Page1 = () => {
const url = 'https://reqres.in/api/users'
const [users, setUsers] = useState()
useEffect(() => {
console.log('component got loaded')
getUsers()
}, [])
const getUsers = () => {
fetch(url)
.then((result) => result.json())
.then((result) => {
setUsers(result)
})
}
return (
<div>
<h1 className="page-title">Users List</h1>
<table className="table table-stripped">
<thead>
<tr>
<th>Avatar</th>
<th>Id</th>
<th>Email</th>
<th>First Name</th>
<th>Last Name</th>
</tr>
</thead>
<tbody>
{users &&
users.data.map((user) => {
return <UserTableRow user={user} />
})}
</tbody>
</table>
</div>
)
}
export default Page1
Signup Component + Axios HTTP
yarn add Axios
Create Signup Code in Signup.js
import { useState } from 'react'
// imoprt axios to make the APIs calls
import axios from 'axios'
const Signup = () => {
const url = 'http://localhost:4000/user/signup'
// initially all the user input values will be empty
const [userName, setUserName] = useState('')
const [email, setEmail] = useState('')
const [password, setPassword] = useState('')
const signupUser = () => {
// call the POST api
axios
.post(url, {
name: userName,
email,
password,
})
.then((response) => {
// read the response sent by the server
const result = response.data
if (result['status'] === 'success') {
alert('new user signed up')
} else {
alert('error while signing up the user')
}
})
.catch((error) => {
alert(error)
})
}
return (
<div>
<h1 className="page-title">Signup</h1>
<div className="form-group">
<div className="mb-3">
<label className="form-label">Full name</label>
<input
onChange={(e) => {
setUserName(e.target.value)
}}
type="text"
className="form-control"
/>
</div>
<div className="mb-3">
<label className="form-label">Email address</label>
<input
onChange={(e) => {
setEmail(e.target.value)
}}
type="email"
className="form-control"
placeholder="name@example.com"
/>
</div>
<div className="mb-3">
<label className="form-label">Password</label>
<input
onChange={(e) => {
setPassword(e.target.value)
}}
type="password"
className="form-control"
placeholder="*******"
/>
</div>
<div className="mb-3">
<p>Already have an account? Sign in here.</p>
<button onClick={signupUser} className="btn btn-success">
Signup
</button>
</div>
</div>
</div>
)
}
export default Signup
Output
React Toastify
React-Toastify allows you to add notifications to your app with ease.
yarn add react-toastify
Add in app.js the dependency for react-toastify
import { ToastContainer } from 'react-toastify'
import 'react-toastify/dist/ReactToastify.css'
<ToastContainer />
In the SignUp.js, update the toast fields
import { toast } from 'react-toastify'
const signupUser = () => {
if (userName.length === 0) {
toast.warning('please enter user name')
} else if (email.length === 0) {
toast.warning('please enter email')
} else if (password.length === 0) {
toast.warning('please enter password')
} else {
// call the POST api
axios
.post(url, {
name: userName,
email,
password,
})
.then((response) => {
// read the response sent by the server
const result = response.data
if (result['status'] === 'success') {
toast.success('new user signed up')
} else {
toast.error('error while signing up the user')
}
})
.catch((error) => {
toast.error(error)
})
}
}
Output
React Router
yarn add react-router-dom
iimport { BrowserRouter, Link, Route, Routes } from 'react-router-dom'
const Component1 = () => {
return <h1 className="page-title">Component 1</h1>
}
const Component2 = () => {
return <h1 className="page-title">Component 2</h1>
}
const Component3 = () => {
return <h1 className="page-title">Component 3</h1>
}
function App() {
return (
<div className="container">
<BrowserRouter>
<Link to="/c1">Component 1</Link>
<Link to="/c2">Component 2</Link>
<Link to="/c3">Component 3</Link>
<Routes>
<Route path="/page1" element={<Page1 />} />
<Route path="/signup" element={<Signup />} />
<Route path="/signin" element={<Signin />} />
<Route path="/home" element={<Home />} />
<Route path="/c1" element={<Component1 />} />
<Route path="/c2" element={<Component2 />} />
<Route path="/c3" element={<Component3 />} />
</Routes>
</BrowserRouter>
<ToastContainer />
</div>
)
}
Storage
There are scenarios when we need to get data from the browser, i.e it would be difficult to always call the backend to get data from a server or database.
There are two kinds of preferred storage in React i.e Session & Local Storage. Both Session and Local Storage will typically be able to store around 5 MB of data per domain, which is significantly more than cookies(4K).
- Session Storage
- SessionStorage gets cleared when the browsing session ends (i.e. when the browser / browser tab is closed), two tabs loaded with the same website will have different sessionStorage data, however sessionStorage data survives page refresh.
- Local Storage
- LocalStorage data, is shared between all tabs and windows from the same origin. LocalStorage data does not expire; it remains after the browser is restarted and even after OS reboot. LocalStorage is available on all browsers, but persistence is not consistently implemented. For ex: Chrome allows users to explicitely clear local storage from settings.
Storing in Session Storage
// cache properties inside session storage
// if the keys do not exist, then they will get created with the current values
// if exist then the values will get overwritten
sessionStorage['username'] = name
sessionStorage['email'] = email
sessionStorage['token'] = token
Retrieving from Session Storage
sessionStorage['username']
Output with Stored data seen in Session storage.
Redux
Redux is global storage that can be used across components. A Predictable State Container for JS AppsGet Started, Redux is an open-source JavaScript library for managing and centralizing the application state. It is most commonly used with libraries such as React or Angular for building user interfaces. Similar to (and inspired by) Facebook’s Flux architecture, it was created by Dan Abramov and Andrew Clark.
Create a new APP : npx create-react-app redux-demo
Add redux dependencies: yarn add redux-devtools redux react-redux
Step 1: Create Two components First.js, & Second.js to interact between each other
import { useState } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { increment } from '../actions/counterActions'
const First = () => {
// get the counter from global store
const counter = useSelector((state) => state.counter)
// use dispatch to dispatch an action to the reducer
const dispatch = useDispatch()
const onIncrement = () => {
dispatch(increment())
}
return (
<div>
<h1>First Component</h1>
<p>Count {counter}</p>
<button onClick={onIncrement}>Increment</button>
</div>
)
}
export default First
import { useState } from 'react'
import { useDispatch, useSelector } from 'react-redux'
import { decrement } from '../actions/counterActions'
const Second = () => {
// get the counter from global store
const counter = useSelector((state) => state.counter)
// use dispatch to dispatch an action to the reducer
const dispatch = useDispatch()
const onDecrement = () => {
dispatch(decrement())
}
return (
<div>
<h1>Second Component</h1>
<p>Count {counter}</p>
<button onClick={onDecrement}>Decrement</button>
</div>
)
}
export default Second
Step 2: Create a countReducer.js inside reducers Folder
const countReducer = (state = 0, action) => {
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return state - 1
default:
return state
}
}
export default countReducer
Step 3: Create a global store store.js
import { combineReducers, createStore } from 'redux'
import counter from './reducers/countReducer'
// create a global store
const store = createStore(combineReducers({ counter }))
export default store
Step 4: Use a Provider in index.js for all components in APP
import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'
import reportWebVitals from './reportWebVitals'
import { Provider } from 'react-redux'
import store from './store'
ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>,
document.getElementById('root')
)
reportWebVitals()
Step 5: Add to App.js
import logo from './logo.svg'
import './App.css'
import First from './components/First'
import Second from './components/Second'
function App() {
return (
<div className="App">
<First />
<hr />
<Second />
</div>
)
}
export default App
Step 6: Output