What is the React Component API?
React introduced Hooks in version 16.8 which lets users create components that access state without writing class components. This has drawn many developers away from the classic class components. However, Hooks don’t replace class components. They simply offer a different method for creating components.
In the article, I will make notes on what an equivalent React Hook function may be.
The React Component API allows users to access functions for:
- state changes
- lifecycle stages
- rendering
React uses Javascript to render HTML and CSS to webpages. This is done using the Document Object Model (DOM). The DOM is how programming languages access webpages.
When starting out, do not get caught up on the DOM. You will interact with it at a higher level. However, the process of using the DOM to manage what components appear on the webpage—and what they display—gives us the component lifecycle.
A component’s lifecycle consists of mounting, updating, and unmounting. The React Component API opens up functions that allow us to push into this cycle and run code at certain times.
Javascript Classes
import React from 'react' class Title extends React.Component { .... }
We can use the React Component API by taking advantage of Javascript’s object-oriented programming implementation.
The above code is an example of creating a component class in React. We are defining the class Title
and extending it with the React.Component
class that is imported with the React library at the top of the code.
This is one way to define a component in React and gain access to the API functions in React.Component
.
You call the constructor()
method inside of a class to define values for the class when the instance is initialized. In React, these values are the state of the component.
import React from 'react' class Title extends React.Component { constructor(props) { // define state } }
However, before we start defining state values, we need to call the super()
function inside of the constructor()
function.
Many newcomers struggle to grasp these function calls. Therefore, we are going to break down this first part of declaring a class component in React.
constructor()
and super()
The constructor is going to allow us to initialize the state of the component with values. For example, if I was defining a component named Person
, I could initialize that person with a starting value for age or name.
import React from 'react' class Person extends React.Component { constructor(props) { this.state = { name: 'Jane Doe', age: 0 } } }
However, this would cause an error. We cannot use the this
keyword to access the current instance until we call super()
.
We are ‘extending’ the parent class (React.Component
) with our new class (Title
). We must reconcile the creation of the two objects before accessing the instance.
If this.state
was also defined in the React.Component
class, we would have a problem. The value is trying to be initialized in two places.
The reasons for calling super()
are difficult to grasp. Regardless, they exist and we have to remember to use the super()
function.
import React from 'react' class Person extends React.Component { constructor(props) { super(props); this.state = { name: 'Jane Doe', age: 0 } } }
You have probably noticed the props
argument that is passed to the constructor(props)
function and then to super(props)
. This also addresses initializing the base class (React.Component
) with the component’s props. The parent class needs to know about the values in the new class.
Finally, still inside of the constructor function, we can initialize the state of the component.
We have successfully started defining the component class. The React.Component
class provides a variety of functions that can be called, but one function has to be called: render()
.
import React from 'react' class Person extends React.Component { constructor(props) { super(props); this.state = { name: 'Jane Doe', age: 0 } } render() { return ( <p>Hi, my name is {this.state.name}</p> ) } }
So far we have looked at two functions in the component API: constructor
and render
. Next, let’s look at the other lifecycle functions in the API that we can use in the component!
React Component API
The function call names provide hints as to when they are called in the component lifecycle. When a component is added to the DOM, it has “mounted”. When it is removed the DOM, it is “unmounted”. A component updates when it’s props or state change.
In the following sections, I will try to shed light on how to use the API. In the examples below I will be using Create React App (CRA). This is a common way to quickly get started using React. Follow this link if you would like to install the project and follow along!
componentDidMount()
To use the component API in React, we need to set up a class component. Let’s start with a simple component. If you are coding along with me, replace the code in src/App.js
with the code below.
import React from 'react'; import logo from './logo.svg'; import './App.css'; class App extends React.Component { constructor(props) { super(props); this.state = { name: 'Jane Doe', age: 0 } } render () { return ( <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> <p>Hello, my name is {this.state.name}.</p> </header> </div> ) } } export default App;
None of this should be new. We are naming the component and are calling the constructor
and render
functions. If you have a development server running for your CRA project your screen will display the React logo.
In the React documentation, it’s said that componentDidMount
is called immediately after the component is added to the tree (DOM). This makes it a good place to make HTTP calls to APIs to retrieve data.
Next, let’s add the componentDidMount
function and simulate an API call with the global setTimeout
function. In this function, we will update the name in the component’s state.
Add this code in between the constructor
and render
functions:
.. componentDidMount() { console.log('Mounted') setTimeout(() => { this.setState({ name: 'John Doe' }) }, 3000) } ..
The component:
- Mounts with the name ‘Jane Doe’
- Runs the
componentDidMount
function - Updates the state
- Renders the new name value to display ‘John Doe’
This function is popular when React is used in the front-end. Components can get up-to-date information every time they mount by reaching out to the network (i.e database, server, etc.).
Equivalent React Hook
A function that is used in the same way for React Hooks is the useEffect
function.
componentDidUpdate()
Another function that the React component API provides is componentDidUpdate
. This function is called if the component updates. This happens in the middle of the component lifecycle.
A component may receive different props through user interaction, or the state may be modified. If either of these occur, this function can be a place to insert logic to do several things. To name a few, it could:
- verify new values
- change the display based on new props
- send a network request
- update state based on changing props
In the React documentation, there is a warning that we should be cautious to not cause an infinite loop if we are modifying state in this function. If we are modifying state (outside of a conditional that is making decisions based on the component props) then this function will run in an infinite loop.
A good way to test if you have created an infinite loop is to log something to the console in the componentDidUpdate
function to see how many times this function runs when the component mounts.
Underneath the componentDidMount()
, in App.js
, add the below code.
.. componentDidUpdate(prevProps) { if (prevProps !== this.props) { console.log('Something changed, send a network call to update state') } else { console.log("Props didn't change, no need to update state.") } } ..
Then, save the file, and open up your browser’s console to view the output.
Initially, Mounted
is logged after the component mounts. Remember that we modify the state in the function after 3 seconds.
When the state is updated, componentDidUpdate
is triggered. We have inserted some simple logic to compare the props to the previous props (we are not passing in any new props) and then perform an action based on the comparison.
Since the props do not change, Props didn't change, no need to update state.
is logged to console after 3 seconds.
Brief Review
Before moving on let’s review how these functions work together;
- The component is mounted to the DOM
componentDidMount
executes (typically to grab data from the network and update state)componentDidMount
only runs once
componentDidUpdate
runs anytime the props or the state change, because components re-render if values change.- You can also send network requests in
componentDidUpdate
, but check the props to avoid an infinite loop if updating the state.
- You can also send network requests in
So far, we have looked at functions that help us manage components at the beginning and middle of their lifecycles. Next, we talk about the function used at the end of the lifecycle.
componentWillUnmount()
This function is called before a component is removed from the DOM. It’s not considered a rare function, as far as the API is concerned, but you probably won’t use it as much as the previous two functions discussed. In the React documentation, there are a few examples of what can be done in this function:
- invalidating timers
- canceling network requests
- cleaning up any subscriptions
An advanced example of this function is if you have set up a connection for real-time data with socket.io. If a connection was created in componentDidMount
, you can safely clean up the connection in componentWillUnmount()
.
In our example, we are going to move the <p>
element that displays the name into its own component. Then we will add a button that toggles the display of that element. This will allow us to mount and unmount our new component with the click of the button.
Finally, we are adding the componentWillUnmount
function to the new component and logging a message to the console in the function.
import React from 'react'; import logo from './logo.svg'; import './App.css'; // The new component class Name extends React.Component { // Log a goodbye message to the console when the component unmounts componentWillUnmount() { console.log(`Goodbye ${this.props.personName}`) } render() { return ( <p>Hello, my name is {this.props.personName}</p> ) } } class App extends React.Component { constructor(props) { super(props); this.state = { name: 'Jane Doe', age: 0, // Add a state variable to control the visibility of the Name component showName: true } // Bind the function that controls the state value for showName this.onChangeShowName = this.onChangeShowName.bind(this); } componentDidMount() { console.log('Mounted') setTimeout(() => { this.setState({ name: 'John Doe' }) }, 3000) } componentDidUpdate(prevProps) { if (prevProps !== this.props) { console.log('Something changed, send a network call to update state') } else { console.log("Props didn't change, no need to update state.") } } // Toggle the show value in state based on the previous value onChangeShowName() { this.setState((state) => { return { showName: !state.showName } }); } render () { return ( <div className="App"> <header className="App-header"> <img src={logo} className="App-logo" alt="logo" /> {/* Add a button to control whether or not to show the Name component */} <button onClick={() => this.onChangeShowName()} >Show Name</button> {/* Ternary expression to control whether or not to display the Name component */} {this.state.showName ? <Name personName={this.state.name} /> : null} </header> </div> ) } } export default App;
This greatly increased the code in the file, but I have added comments to help describe the new code and what it does. The app should now have a button to toggle the display of the greeting.
In the console, if we only clicked the toggle button once, the output will be:
The Name
component is displayed until the button is clicked. When the button to toggle the display is clicked, the Name
component is removed from the DOM. However, before it is removed, the code in componentWillUnmount
is run and Goodbye John Doe
is logged to the console.
Notice that the main App
component’s state changes when the button is clicked. This again runs the code in componentDidUpdate
.
Equivalent React Hook
The useEffect
hook is versatile. In the documentation, this hook is used in place of componentWillUnmount
function. To see an example, check out the documentation.
setState()
Modifying a component’s state directly can cause problems. Therefore, React’s Component API provides the function for ease-of-use. We set the state of the component twice in the above example file and utilized two different styles for setting the state.
In componentDidMount
, we set the state by passing in an object that changed the value of a single state property.
In onChangeShowName
, we set the state based on the previous state. This was done by passing a callback function into the setState
function. If we pass a callback function into setState
, we need to remember to pass the previous state as an argument to that callback function.
onChangeShowName() { this.setState((state) => { return { showName: !state.showName } }); }
The argument state
that is passed into the callback holds the previous state. We can access the previous showName
value on this object.
Equivalent React Hook
With React Hooks, the state is managed differently. Instead of using a function like setState
, state values are declared with the useState
hook.
Conclusion
I hope you can start to see the bigger picture for managing a component through the Component API. React has some quirks that can be learned but it helps to remember the API by thinking about its lifecycle.
Although this covered the main functions, the React Component API has other functions that are considered “rare”. You can read more about the rare functions in the documentation.
React may be moving away from class-based components, but many applications still use this API. That makes these functions relevant to the modern React developer. I recommend trying to build the same component using both approaches to see how the implementation changes. Good luck!
FAQ
What is the React Component API?
React introduced Hooks in version 16.8 which lets users create components that access state without writing class components. This has drawn many developers away from the classic class components. However, Hooks don’t replace class components. They simply offer a different method for creating components. In the article, I will make notes on what an equivalent React Hook function may be.
How to fetch data with react hooks?
Use can fetch data with the useEffect or useState hook. Find a detailed example at https://rapidapi.com/blog/react-hooks-fetch-data-api/
How to fetch data from a graphql api in react?
Set-up the project, Get an API key, fetch the GraphQL data, and display the GraphQL data response. See an example at: https://rapidapi.com/blog/graphql-react-fetch-data/
Leave a Reply