React Basic 4/7 5/7 6/7 7/7
21 Feb 20224/7
Lifecycle Methods
ONLY available for a Class Component. DO NOT exist for a functional component.
-
Mounting : When an instance of a component is being created and inserted into the DOM
constructor, static getDerivedStateFromProps, render, componentDidMount
-
Updating: When a component is being re-rendered as a result of changes to either its props or state
static getDerivedStateFromProps, shouldComponentUpdate, render, getSnapshotBeforeUpdate, componentDidUpdate
-
Unmounting: When a component is being removed from the DOM
componentWillUnmount
-
Error Handling: When there is an error during rendering, in a lifecycle method, or in the constructor of any child component
static getDerivedStateFromError, componentDidCatch
Mounting
- constructor(props)
- called whenever a new component is created
- Initializing state and binding the event handlers
- have to call
super(props)which will call the baseclass Constructorand overwritethis.state - only place where you can directly change
stateby assigning. In all other scenarios, one has to usethis.setState - Never make http requests from within a constructor
- static getDerivedStateFromProps(props, state)
- Used when we want to initialize the initial
stateof a component with the data that is passed inprops - Since this is a static method, this method has no access to
thiskeyword. - Never make http requests from within a constructor
- Used when we want to initialize the initial
- render()
- only required method
- read
propsandstateand return the JSX - Never change state, or interact with DOM or make ajax calls
- children components lifecycle methods are also executed
- componentDidMount()
- called only once
- invoked immediately after a component and all its children components have been rendered to the DOM
- Perfect place to interact with DOM or perform any ajax calls to load data
Example:
Component A = parent.
Component B = Child of A
Mounting Lifecycle chronology:
- LifecycleA constructor
- LifecycleA getDerivedStateFromProps
- LifecycleA render
- LifecycleB constructor
- LifecycleB getDerivedStateFromProps
- LifecycleB render
- LifecycleB componentDidMount
- LifecycleA componentDidMount
Updating
- static getDerivedStateFromProps()
- called every time a component is rendered
- set the state
- DO NOT make HTTP request
- shouldComponentUpdate(nextProps, nextState)
- dictates if the components should re-render or not
- used for performance optimization
- DO NOT call the setState method or make HTTP request
- render()
- ONLY required method
- read
propsandstateand return the JSX - Never change state, or interact with DOM or make ajax calls
- getSnapshotBeforeUpdate(prevProps, prevState)
- called right before the changes from the virtual DOM are to be reflected in the DOM
- Capture some information from the DOM (Example: capture users scroll position and after the update, maintain that scroll position by performing some calculation)
- returns null or a value.
- returned value (a snapshot) will be passed as the third parameter to the next method
- componentDidUpdate(prevProps, prevState, snapshot)
- called after the render is finished in the re-render cycles
- guaranteed to be called only once in every re-render cycle
- can make ajax call or http requests
Updating Lifecycle chronology:
After the mounting lifecycle is completed:
- LifecycleA getDerivedStateFromProps
- LifecycleA shouldComponentUpdate
- LifecycleA render
- LifecycleB getDerivedStateFromProps
- LifecycleB shouldComponentUpdate
- LifecycleB render
- LifecycleB getSnapshotBeforeUpdate
- LifecycleA getSnapshotBeforeUpdate
- LifecycleB componentDidUpdate
- LifecycleA componentDidUpdate
Unmounting
- componentWillUnmount()
- this method is invoked immediately before a component is unmounted and destroyed
- cancelling any network requests, removing event handlers, cancelling any subscriptions and also invalidating timers
- NOT call the
setStatemethod
Error Handling
- static getDerivedStateFromError(error)
- componentDidCatch(error, info)
Ref:
5/7
Fragment
In react, adjacent JSX elements must be wrapped in an enclosing tag.
Example:
import React from 'react'
function ComponentName(){
return (
<h1> Hello, Jeet</h1>;
<p> This is a description </p>
)
}
export default ComponentName
The above script WILL NOT WORK.
However, the script below will work.
import React from 'react'
function ComponentName(){
return (
<div>
<h1> Hello, Jeet</h1>;
<p> This is a description </p>
</div>
)
}
export default ComponentName
To prevent addition of extra node in DOM, we can use React.Fragment
import React from 'react'
function ComponentName(){
return (
<React.Fragment>
<h1> Hello, Jeet</h1>;
<p> This is a description </p>
</React.Fragment>
)
}
export default ComponentName
key attribute is the only attribute that can be passed to react fragment.
Shortcut for <React.Fragment> is <> and that of </React.Fragment> is </>
Refs
- To create a ref we use
React.createRef()method. - Attach this ref to our input element of our render method.
- Use it
import React, {Component} from 'react'
class RefsDemo extends Component {
constructor(props) {
super(props)
this.inputRef = React.createRef()
}
componentDidMount(){
this.inputRef.current.focus()
console.log(this.inputRef)
}
render(){
return(
<div>
<input type = "text" ref={this.inputRef}/>
</div>
)
}
}
Refs with Class Components
Call a child function from a parent function
Input.js
import React, {Component} from 'react'
class RefsDemo extends Component {
constructor(props) {
super(props)
this.inputRef = React.createRef()
}
focusInput(){
this.inputRef.current.focus()
}
render(){
return(
<div>
<input type = "text" ref={this.inputRef}/>
</div>
)
}
}
FocusInput.js
import React, { Component } from 'react'
import Input from './Input'
class FocusInput extends Component {
constructor(props){
supur(props)
this.componentRef = React.createRef()
}
clickHandler = () => {
this.componentRef.current.focusInput() // focusInput is the fucntion in 'Input.js'
}
render(){
return (
<div>
<Input ref={this.componentRef} />
<button onClick={this.clickHandler}> Focus Input </button>
</div>
)
}
}
-
Forwarding Refs
(To allow the parent component to directly reference the native input element with some props loaded)
FRInput.js
import React from 'react'
const FRInput = React.forwardRef((props, ref) => {
return (
<div>
<input type="text" ref={ref} />
</div>
)
})
export default FRInput
The child element is basically forwarding this reference.
FRParentInput.js
import React, { Component } from 'react'
import FRInput from './FRInput'
class FRParentInput extends Component {
constructor(props){
supur(props)
this.inputRef = React.createRef()
}
clickHandler = () => {
this.inputRef.current.focus()
}
render() {
return(
<div>
<FRInput ref={this.inputRef}/>
<button onClick={this.clickHandler}>Focus Input </button>
</div>
)
}
}
Portals
Usually everything you create, goes under the App component with id='root'.
To create a different node and attach components under that new node, react provides portals.
React Portals lets us create any component under any DOM node.
In the index.html, create a new div under the div with id = root.
<div id='portal-root'> </div>
Now create a functional component to be added under this new div.
import React from 'react'
import ReactDOM from 'react-dom'
function PortalDemo() {
return ReactDOM.createPortal(
<h1>
Portals Demo
</h1>,
document.getElementById('portal-root')
)
}
Ref:
6/7
Higher Order Component - HOC
A pattern where a function takes a component as an argument and returns a new component.
In code:
const NewComponent = higherOrderComponent( originalComponent )
Example:
const IronMan = withSuit( TonyStark )
Lets create our HOC
withCounter.js
import React from 'react'
const UpdatedComponent = (OriginalComponent, incrementNumber) => {
class NewComponent extends React.Component {
constructor(props){
super(props)
this.state = {
count: 0
}
}
incrementCount = () => {
this.setState(prevState => {
return {count: prevState.count + incrementNumber}
})
}
render() {
return<OriginalComponent name="Jeet" count={this.state.count} incrementCount={this.incrementCount} {...this.props} />
}
}
return NewComponent
}
export default UpdatedComponent
HoverCounter.js
import React, { Component } from 'react'
import UpdatedComponent from 'withCounter'
class HoverCounter extends Component {
render(){
const { name, count, incrementCount } = this.props
return (
<h2 onMouseOver={incrementCount}>
{name} Hovered {count} times
</h2>
)
}
}
export default UpdatedComponent(HoverCounter, 5)
Render Props
The term “render props” refers to a technique for sharing code beween React components using a prop whose value is a function
Example 1:
App.js
import React, { Component } from 'react'
import './App.css'
import ClickCounterTwo from './Component/ClickCounterTwo'
import User from './Components/User'
class App extends Component {
render(){
return (
<div className="App">
<ClickCounterTwo />
<User name={(isLoggedIn) => isLoggedIn ? 'Viswas' : 'Guest'} />
</div>
)
}
}
export default App
User.js
import React, { Component } from 'react'
class User extends Component {
render(){
return (
<div>
{this.props.name(false)}
</div>
)
}
}
export default User
Example 2:
Create a props with the name render and just define the function arguments
Counter.js
import React, { Component } from 'react'
class Counter extends Component {
construnctor(props){
super(props)
this.state = {
count: 0
}
}
imcrementCount = () => {
this.setState(prevState => {
return { count: prevState.count + 1}
})
}
render(){
return(
<div>
{this.props.render(this.state.count, this.incrementCount)}
</div>
)
}
}
export default Counter
Now create the function with the same name render i,e Render props that will use these parameters:
App.js
import React, { Component } from 'react'
import './App.css'
import ClickCounterTwo from './Component/ClickCounterTwo'
import Counter from './Components/Counter'
class App extends Component {
render(){
return (
<div className="App">
<Counter render={(count, incrementCount) => (<ClickCounterTwo count={count} incrementCount={incrementCount} />) }
/>
</div>
)
}
}
export default App
ClickCounterTwo.js
import React, { Component } from 'react'
class App extends Component {
render(){
const { count, incrementCount } = this.props
return <button onClick={incrementCount}> Clicked {count} times </button>
}
}
export default ClickCountTwo
Context
Context provides a way to pass data through the component tree without having to pass props down manually at every level.
-
Create the Context
-
Provide a context value
-
Consume the context value
Wrap the root Component in a Provider Context, and then use it in any child Component using Consumer Context
AppComponent (source)
C
E
F (target)
userContext.js
import React from 'react'
const UserContext = React.createContext()
// to provide a default value to the contexts, use
// const UserContext = React.createContext("dafault_value")
const UserProvider = UserContext.Provider
const UserConsumer = UserContext.Consumer
export { UserProvider, UserConsumer }
App.js
import React, { Component } from 'react'
import './App.css'
import ComponentC from './Components/ComponentC'
import { UserProvider } from './Components/userContext'
class App extends Component {
render() {
return (
<div className="App">
<UserProvider value="Jeet">
<ComponentC />
</UserProvider>
</div>
)
}
}
ComponentF.js
import React, { Component } from 'react'
import { UserConsumer } from './userContext'
class ComponentF extends Component {
render(){
return(
<UserConsumer>
{
(username) => {
return <div>Hello {username}</div>
}
}
</UserConsumer>
)
}
}
export default ComponentF
Intermediate Components:
ComponentC.js
import React, { Component } from 'react'
import ComponentE from './ComponentE'
class ComponentC extends Component {
render(){
return <ComponentE />
}
}
export default ComponentC
ComponentE.js
import React, { Component } from 'react'
import ComponentF from './ComponentE'
class ComponentE extends Component {
render(){
return <ComponentF />
}
}
export default ComponentE
For Multiple Contexts:
function Context(){
return(
<ThemeContext.Consumer>
{theme => (
<UserContext.Consumer>
{user => (
<ProfilePage user={user} theme={theme} />
)}
</UserContext.Consumer>
)}
</ThemeContext.Consumer>
);
}
Ref:
7/7
React and HTTP Library - axios
Axios is one of the http libraries used to handle GET and POST request in React
PosForm.js
import React, { Component } from 'react'
import axios from 'axios'
class PostForm extends Component {
constructor(props) {
super(props)
this.state = {
userId: '',
title: '',
body: ''
}
}
changeHandler = e => {
this.setState({ [e.target.name]: e.target.value })
}
submitHandler = e => {
e.preventDefault()
console.log(this.state)
axios.post('https://jsonplaceholder.typicode.com/posts', this.state)
.then(response => {
console.log(response)
})
.catch(error => {
console.log(error)
})
}
render() {
const { userId, title, body } = this.state
return (
<div>
<form onSubmit={this.submitHandler}>
<div>
<input
type="text"
name="userId"
value={userId}
onChange={this.changeHandler}
/>
</div>
<div>
<input
type="text"
name="title"
value={title}
onChange={this.changeHandler}
/>
</div>
<div>
<input
type="text"
name="body"
value={body}
onChange={this.changeHandler}
/>
</div>
<button type="submit">Submit</button>
</form>
</div>
)
}
}
export default PostForm
PostList.js
import React, { Component } from 'react'
import axios from 'axios'
class PostList extends Component {
constructor(props) {
super(props)
this.state = {
posts: [],
errorMsg: ''
}
}
componentDidMount() {
axios.get('https://jsonplaceholder.typicode.com/posts')
.then(response => {
console.log(response)
this.setState({ posts: response.data })
})
.catch(error => {
console.log(error)
this.setState({errorMsg: 'Error retrieving data'})
})
}
render() {
const { posts, errorMsg } = this.state
return (
<div>
List of posts
{posts.length
? posts.map(post => <div key={post.id}>{post.title}</div>)
: null}
{errorMsg ? <div>{errorMsg}</div> : null}
</div>
)
}
}
export default PostList
App.js
import React, { Component } from 'react'
import './App.css'
import PostList from './components/PostList'
import PostForm from './components/PostForm'
class App extends Component {
render() {
return (
<div className="App">
<PostForm />
{/* <PostList /> */}
</div>
)
}
}
export default App
Ref: