React development has never been the same since the release of functional components in 2019.
I started learning to use React at the time when functional components became a thing, and I never had to use class components in any of my projects.
However, chances are that you may work in a legacy codebase where it would be almost impossible to refactor the codebase to use functional components. In that case, you’d need to learn.
In this article, you’re going to be learning everything you need to make your first contribution to such a codebase. If you’ve got some JavaScript skills, it becomes pretty easy to understand the class component concept in a few hours.
But, how good should I be? Well, I’d say a basic understanding of OOP in JS would be all you need.
Okay, enough talk! Let’s get started
The React class component was introduced in 2013 when they had just released version 0.3.
There are a few things you need to know to become comfortable with React class components, and it’s best to have them listed to make it much easier:
- How they are created
- How states are created and updated
- How props are being read and used
- Side Effects and Lifecycles
A class component is created with an ES6 class that extends React.Component
Let’s start with an example:
import * as React from "react"
class App extends React.Component {}
We basically extended React’s based component so that we get access to the functions available inside of it.
Now, to return markup from the component, we have to call render() inside of it.
An updated version of the code would be something like this:
import * as React from "react"
class App extends React.Component {
render() {
return <div>Hello User</div>
}
}
🤔 But .. where is the render coming from?
Well… Think of React.Component as a base class that every component must extend to get access to all its functions.
So, In our case, we have the App component extends the base class, and we automatically got access to the render function, which is then used return JSX.
Adding States to the component
Okay.. we have a component now, so how do we add a piece of state to it?
It’s very simple.
We can add them to a state object inside of the constructor.
import * as React from "react"
class App extends React.Component {
constructor(props) {
super(props)
state = {
likes: 0
}
}
render() {
return <div>Hello User</div>
}
}
That’s simply all it takes to add a piece of state to a class component.
After creating the state, we can then display the value for the state that we created on the webpage.
You can add more states to the component simply by adding them inside of the states object inside the class’ constructor. e.g:
import * as React from "react"
class App extends React.Component {
constructor(props) {
super(props)
state = {
likes: 0,
name: "Emmanuel Odii",
age: 17
}
}
render() {
return <div>Hello {this.state.name}</div>
}
}
So.. If you’ve used React functional components in the past, you notice that this becomes a downside to class components, because you have to put all your states inside one object, which is preety weird 😞
Updating States in the component
Just as we get access to the state object that is being used in the constructor to add states to the component, we also get access to the setState object from React.Component . this is exactually what we need to update the states we create in our application.
States are updated either by running side-effects in the component or by attaching inside of an event handler
If you don’t know about event handlers, don’t worry. we’d learn about it in a bit.
let’s start with a very simple where we just want to update the likes state that we already created.
import * as React from "react"
class App extends React.Component {
constructor(props) {
super(props)
state = {
likes: 0,
name: "Emmanuel Odii",
age: 17
}
}
// this increments the likes by 1
handleUpdateLikes() {
this.setState(prev => ({ ...prev, count: prev.count + 1 }))
}
render() {
return <div>Hello {this.state.name}</div>
}
}
The function that we just created can be used inside an event handler.
A typical usecase for the example that we’ve been using would be attaching it to the click event of a button on the page.
Adding props to a component and using the prop’s value
One of the most important feature of React is the ability to create and re-use components using their props.
Just like we’ve seen the values that we extend from React’s base component to create and update states, the base component from React also exports a prop value that we can use to read the props that is/are inside the component.
Let’s create a simple UserProfile component that displays information about the user.
After initializing the component, we then create we an instance of the UserProfile component inside the parent component, passing the data to be displayed via props.
class UserProfile extends React.Component {
constructor(props) {
super(props)
}
render(){
const { name, age } = this.props
return (
<section>
<div>UserName: {name}</div>
<div>Age: {age}</div>
</section>
)
}
}
And we can this use the UserProfile component inside the parent component just like so:
import * as React from "react"
class App extends React.Component {
constructor(props) {
super(props)
state = {
likes: 0,
name: "Emmanuel Odii",
age: 17
}
}
// this increments the likes by 1
handleUpdateLikes() {
this.setState(prev => ({ ...prev, count: prev.count + 1 }))
}
render() {
return <UserProfile name={this.state.name} age={this.state.age}/>
}
}
And.. That’s all there is to accepting and reading props in a class component.
Lastly, we need to learn how side effects work in class component.
Side Effects and Lifecycles
Side effects are crucial to understand. it simply helps establish communication with external resources, such as local storage and supports utilizing APIs.
There are some functions that React’s base component gives us access to, but out of those, we most likely will work with 3 most time.
They are componentWillMount(), componentDidMount(), componentDidUpdate()
- The componentWillMount() lifecycle method in React class components is invoked just before a component is mounted (added to the DOM).
- The componentDidMount() lifecycle method in React class components is invoked immediately after a component is mounted(added to the DOM)
Thinking about it in React functional term, it’s simply initializing the useEffect hook with an emtpy dependency array. - The componentWillUpdate() lifecycle method in React class components is invoked immediately after a component is mounted(added to the DOM), and during subsequent re-renders of the component.
It accept two parameters (the previous and current version of the render), and then we can check to see if a state changed so that we can perform some logic .
Thinking about it in React functional term, it’s simply initializing the useEffect hook with an the values you check for inside of the function as the dependency array.
Again, let’s understand how to create it:
class App extends React.Component {
constructor(props) {
super(props)
state = {
likes: 0,
}
}
componentWillMount() {
console.log("Component want's to mount");
}
componentDidMount() {
console.log('Component did mount');
}
componentDidUpdate(prevProps, prevState) {
if (prevState.likes !== this.state.likes) {
console.log('Likes got updated:', this.state.likes);
}
}
render(){
return <div>Hello world</div>
}
}
And.. that’s all you’d need to contribute to a codebase that uses React’s old class components.
If you found this helpful, please consider following me on Linkedin, reacting to this post, leaving a comment, or support me by buying me a coffee through this link.