Overview
I started to write this just about Lifecycle Methods but realized that an intro about React might be helpful.
When I began learning React, I jumped into the syntax without fully understanding the methodologies behind them. So perhaps this will benefit someone else in the same boat.
While this is by no means an all-inclusive or exhaustive introduction, below are some things I found helpful in understanding this powerful library and it's lifecycle methods.
Of course, feel free to jump straight to the lifecycle.
So... what is React?
Intro to React
React, is an amazing front-end JS library that allows you to build super performant single-page applications, with tremendous efficiency.
What is a single-page application?
These are web applications that only serve one HTML file. Even if the user can navigate to 5 different pages, filled with loads of content — only one HTML file is provided by the server. (React is not limited to this setup, but it is most known for it.)
How is that possible?
This is accomplished by updating the DOM (what you see in the browser) in a continuous and intelligent way, while leveraging JavaScript to write most of the site's code. 1 HTML file and a load of very thoughtful JavaScript makes the website...just...React.
(Glad to be the first one to make that joke. 😜)
Ok, but how is THAT possible?
Among other things, React has a few very important tricks up its sleeve.
JSX
JSX is Javascript hybrid language that lets you write HTML, CSS, and JavaScript seamlessly on the same line, with only minor syntax changes. (🤯)
React then renders and compiles the JSX into standard HTML/CSS/JS for the browser to read.
For me personally, JavaScript didn't really click until I started writing JSX and saw the structure and functionality come together...
<section>
<h2>{paginationState ? "New Dev Work" : "More Dev Work"}</h2>
<div className="justify-content-around">
{projects.map(project => (
<DevProjectCard
key={project.id}
img={project.img}
title={project.title}
/>
))}
</div>
</section>
Components
Components are a way to break up JSX and pure JS (like API calls) into separate files. Modularization and Separation of Concerns are concepts that fit nicely here.
While the concept of components is not unique to React, it is pretty synonymous with it. The idea is to have many small/lean component files, that each holds a little bit of feature-specific code. These are then combined together, creating more complex layouts.
The benefit? Components can be reused in multiple places and their styles/functionality can travel with them. This can mean less coding and maintenance in the long run.
In the example above, the <DevProjectCard />
block of code was a component. It represents another file that holds code (JSX) on how the Dev Project Card should look and function.
Props
Now that the application is divided up into bite-sized components, we need a way to pass information between them. This is where Props come in.
Props take information from a parent component and pass it down to a child component.
This means children components can focus on just providing structure for information but do not need to worry about what the actual info is.
(It is important to note that props can only travel down. A child component can't pass information back up to its parent.)
In our example, <DevProjectCard />
provides a way for an image and title to look in some sort of UI card element. But we are using props img={}
and title={}
to pass down what the actual image and title should be. By not hardcoding the information into <DevProjectCard />
, this component can be used in more places and ways.
<DevProjectCard
key={project.id}
img={project.img}
title={project.title}
/>
Note: The above example is using a .map()
array method to create multiple <DevProjectCard />
components, each with unique images and titles. The key={}
is actually not a prop, but a method that is required on dynamically generated mapped lists in React.
State
Another essential way to handle information and functionality in React is by using something called State.
State lets you temporarily store unique information within a component. As soon as the page is refreshed, the state is removed. But until that point, it is a powerful way to quickly control functionality and content.
For example, perhaps we have a button that loads more Dev Project Cards to the page. Using state, we can store a value of true
when that button is clicked.
Then we can reference that state in an HTML headline to dynamically show different text if that state is true or false.
<h2>{paginationState ? "New Dev Work" : "More Dev Work"}
Virtual DOM
The Virtual DOM is a copy of the real DOM the browser uses. This is where everything we have talked about so far comes together!
The real DOM is pretty slow to update and when you change something in the layout, the whole page needs to re-paint.
Instead, React uses this Virtual DOM to compare against the real DOM, seeing if any components have changed. It uses changes in states and props as signals that something is now different.
If a state and/or prop has changed, React uses the Virtual DOM to only update the component(s) that were affected. This means the real DOM does not need to refresh the entire page if one or two things changed. Again 🤯!
But how does it know to do this?
Ok deep breath...So we write powerful JSX in well-organized components, that control their functionality with state and speak to other components with props — all of which is updated for the user via the Virtual DOM...whew. How does the Virtual DOM know when to check for changes in states and props???
React checks for these changes at strategic points and these are called Lifecycle Methods. 🎉
Lifecycle Methods
Lifecycle methods are how React compares the current code against the virtual and real DOMs. It dictates what code should be assessed and at what point.
Before going further it's important to note, that React originally started with using Class-based components. These handle state and pass down props to Presentation (or dumb) components that only display the content. Lifecycle Methods are specifically used in Class-based components.
With the release of version 16.8
React introduced a new toolset called Hooks. Hooks allow you to turn presentational components into functional components that have all the power of their class-based counterparts, but with (usually) less code needed.
The useEffect
hook replaces all lifecycle methods and I will cover it at the end as well. However, many applications still use class-based components, so it is important to understand their lifecycle methods.
It is lifecycle method time!
Below are the three I use the most, but there are more that are less commonly used. In the end, I will include a link to their documentation for further exploration.
componentDidMount()
This will execute any code inside of it, directly after a component is mounted in the DOM. One of many use cases for this is making an API call for new data.
componentDidMount() {
axios.get('https://api.website/users')
.then(res => {
this.setState({ users: res.data });
})
.catch(error => {
console.log(error);
});
}
componentDidUpdate()
This will execute code directly after a component has been updated through state or props.
A common example is recalling an API that was set up in componentDidMount()
to see if there is new data. However, this can lead to infinite loops or at least unintentional network calls.
To prevent this, componentDidUpdate()
provides the optional prevState
and prevProps
arguments to check if the last versions are different. If they are the same, the code won't be run again and nothing will be re-rendered.
componentDidUpdate(prevProps) {
if(this.props.users !== prevProps.users) {
axios.get('https://api.website/users')
.then(res => {
this.setState({ users: res.data });
})
.catch(error => {
console.log(error);
});
}
}
Often times the same code will be run in both methods. componentDidMount()
will set it up and componentDidUpdate
will check for changes. (This is something hooks streamlines.) Because of this, it can be helpful to place the duplicate code into a helper function and call it in both methods.
// Funtion is called when component mounts
componentDidMount() {
this.fetchUsers()
}
// React will call the function if there is a change
componentDidUpdate(prevProps) {
if(this.props.users !== prevProps.users) {
this.fetchUsers()
}
}
// Helper Function
fetchUsers = () => {
axios.get('https://api.website/users')
.then(res => {
this.setState({ users: res.data });
})
.catch(error => {
console.log(error);
});
}
componentWillUnmount()
This will call right before a component is unmounted and destroyed.
It can be used to stop timers and canceling network requests that were first called in componentDidMount()
. This helps prevent memory leakage.
You never call this.setState()
in this method, because that instance of the component will never be rendered again. This can throw off React from reading the state correctly.
In the example below we are telling Axios to eject some interceptors that were set up to handle global errors.
componentWillUnmount() {
axios.interceptors.request.eject(this.reqInterceptor);
axios.interceptors.response.eject(this.resInterceptor);
}
Hooks! (RIP Lifecycle Methods?)
As mentioned, with the release of version 16.8
React introduced Hooks. Class-based components were no longer needed to handle state and updating the Virtual DOM. A new age of coding in React was introduced with functional components and their "import-as-needed" hook counterparts.
In one block of code, the useEffect
hook replaced the functionality of componentWillMount()
, componentWillUpdate()
and componentWillUnmount()
.
useEffect
In its simplest form, useEffect
takes in a call back function and runs on every render, mimicking the componentDidMount()
and componentDidUpdate()
methods.
Every time the useEffect
runs, it creates a new function behind the scenes, tying it to that particular render.
import React, { useEffect } from 'react';
useEffect(() => {
console.log("This runs everytime the component renders.");
});
useEffect
also takes an array as a second parameter. If left empty this will run its code one time when the component mounts. (componentDidMount()
)
useEffect(() => {
console.log("This runs when the component mounts.");
}, []);
The array can also hold one or more props and state values. React compares the last render to this value(s) and if they haven't changed, will skip the effect. But if the value(s) have changed to what was last rendered, the effect will run again. (Just like prevState
and prevProps
.)
useEffect(() => {
setUsers(props.user);
}, [props.user]); // reruns when props updates
The callback function can also return its own function. This is used to clean up any side effects previously run, to prevent memory leaks. Such as subscribing to a network request. (Just like componentWillUnmount()
)
useEffect(() => {
setUsers(props.user);
return = () => {
axios.interceptors.request.eject(this.reqInterceptor);
}
}, [props.user]);
useEffect
also lets you separate concerns, by having multiple useEffect
hooks on the same component. For example, one handles users being changed on props and the other handles animations being triggered.
useEffect(() => {
setUsers(props.user);
}, [props.user]);
useEffect(() => {
triggerTitleAnimation();
}, []);
You did it! 😄
Nice job sticking through the end. Together we went through what makes React so performant.
Summary
JSX combines HTML, CSS, and JavaScript to make writing code more seamless than ever.
Components segment code into separate files and use props to speak to each other.
State stores content and can be used to trigger functionality.
Together Props and State are used to update the Virtual DOM, which creates a super-fast browsing experience.
All of this is managed through Lifecycle methods and their modern hook counterpart, the
useEffect
hook.
I hope this has helped clarify how some of React works and enables you to create something cool. Happy coding! 🤓
Let me know below: Do you reach for lifecycle methods or the useEffect
hook when working in React?
Further Reading
React Documentation on Lifecycle Methods
React Documentation on Hooks
React The Complete Guide
Header image designed with Adobe Photoshop
Top comments (5)
yes...i always use hooks more than lifecycle methods
Cool, thanks for sharing! I also like hooks a lot better myself. However, by learning more about the lifecycle methods, I ended up understanding the hooks even better.
Exactly what I was looking for. Thanks
Awesome, so glad you found it helpful!
Thank you