Imagine you're building a model of a town using LEGO blocks. Each building, tree, car, or any other piece that you might place on your model town can be considered a component. In the world of web development, particularly when using a technology called React, this concept is similar.
A React component is like one of those LEGO pieces. It's a self-contained unit that represents a part of the user interface (UI) in a web application. Just like each LEGO block can be used to construct different parts of your model town and can be reused in different scenarios, a React component can be used to build different parts of a website and can be reused throughout the application.
📝 Components are not a new concept in web development since libraries like bootstrap are already defining bootstrap components like the
navbar
,dropdown list
,modal
, etc.
React.js separates your code into little pieces called Components which can be created/defined using a class syntax (legacy) or as a function syntax. Each component is like a small React application that has its own logic and purpose, which is to display or render some HTML.
Almost any HTML can be encapsulated and coded as a React Component. To do so, every React component needs to have a return
statement that returns some JSX code (HTML + embedded JS). For example, here is the classic bootstrap navbar encapsulated as a React Component.
1import React from 'react'; 2 3// a function component 4function NavBar(props){ 5 return (<nav className="navbar navbar-light bg-light"> 6 <a className="navbar-brand" href="#">Navbar</a> 7 </nav>); 8}
☝️ There is legacy way to use js classes to create components but we don't showcase or recommend it anymore since it was deprecated a long time ago.
Once you have created your first a component, you can include it or use it inside the rest of your code by typing the function name like an HTML <tag>
. For example, if you created a component using the function syntax called Home you can include it in your code using the <Home>
tag like this:
1import React from "react"; 2import ReactDOM from "react-dom"; 3 4// We can use the <Navbar /> component to display at the top of the Home component 5function Home(props){ 6 return ( 7 <div className="container-fluid"> // Notice that in JSX we need to use the attribute name 'className' instead of 'class' 8 <Navbar /> 9 <div> 10 ... The rest of Home's contents ... 11 </div> 12 </div> 13 ); 14} 15 16// Here we tell React to put our main app component <Home /> inside the DOM element with id #myApp 17const root = ReactDOM.createRoot(document.getElementById('myApp')); 18root.render(<Home />); 19
Sometimes a component needs dynamic information to display. For example, we need our <Navbar />
component to show the list of available links and the brand’s logo. We can include that information within the call of the <Navbar />
component just the same way as we do in HTML tags.
1<Navbar foo="bar" foo2="bar2" />
1let menu = [ 2 {label: 'Home', url: '/home'}, 3 {label: 'Contact Us', url: '/contact-us'} 4]; 5<Navbar items={menu} logo="http://path/to/logo.png" />
And, lastly, you should tell React where to render that component into the DOM.
state
We call components in React stateful because they can incorporate custom state
variables (by importing the useState hook) which have the sole purpose of storing the data needed to render the component properly. One obvious use of the state would be if, for example, we have a form with input fields that need to be filled by the user. The data entered by the user will need to be saved somewhere in order to be used. You will need one state
variable for each of the inputs in the form:
1// pick a variable name initial value 2// ⬇ ⬇ 3const [ email, setEmail ] = useState(null); 4// ⬆ 5// pick the modifier name
In another example, let's say that you are developing a <Clock />
component that has to print the current time every second. That means that our component will need a currentDatetime
state variable. This variable will need to be updated every second with the newest current time, each time the variable is updated the component HTML will also be updated and show the new date-time on the screen.
In order for the state to keep a web page up-to-date, it is programmed to re-render the DOM every time it is modified. So you can probably already see how you can take advantage of this feature by keeping your current time inside the state and reassigning it to the most current time every second. Like so:
👇 The following demo updates the current time every second:
When speaking about modifying the value of the state, you have to remember that the state should not be mutated directly.
1 2// asuming you have declared a "count" state like this 3// ↓ variable ↓ modifier 4const [ count, setCount ] = useState(0); 5 6# ❌ WRONG: you cannot directly set the variable count = 2 7count = 2 8 9# ✅ RIGHT: you need to call the setCount function (the modifier) to update the variable 10setCount(2) 11
🔥 The state variables should only be updated by calling their modifiers.
Here is another example using a state variable count
and its modifier function called setCount
in order to create a small counter component:
1import React, { useState } from 'react'; 2import { createRoot } from 'react-dom/client'; 3 4function Counter() { 5 // useState to hold and set the current count 6 const [count, setCount] = useState(0); 7 8 // Function to increment the counter 9 const incrementHandler = () => { 10 setCount(count + 1); 11 }; 12 13 return ( 14 <div> 15 <h1>Count: {count}</h1> 16 <button onClick={incrementHandler}>Increment</button> 17 </div> 18 ); 19} 20
State updates happen in an asynchronous manner, and directly mutating the state creates an opportunity for values to be incorrectly updated and cause data inconsistencies in your web application.
📝 Read more about the use state react hook
The component lifecycle in React refers to the sequence of phases a component goes through from its creation to its removal from the DOM. This lifecycle can be broken down into three main stages: mounting, updating, and unmounting.
Mounting: This is the phase when the component is being created and inserted into the DOM. It involves initialization and setup tasks, such as setting initial state and integrating with other JavaScript frameworks.
Updating: This occurs whenever a component’s state or props change, triggering a re-render of the component. This phase can involve data fetching, computations, and working with the DOM based on new props or state.
Unmounting: This final phase happens when the component is being removed from the DOM, which is a good time to perform cleanup tasks like invalidating timers, canceling network requests, or cleaning up subscriptions to avoid memory leaks.
useEffect
Hook and LifecycleReact introduced hooks in version 16.8 to allow functional components to manage state and side effects—tasks traditionally handled in class components using lifecycle methods like componentDidMount
, componentDidUpdate
, and componentWillUnmount
. The useEffect
hook serves to encapsulate the functionality of these lifecycle methods into one API, making it possible to perform side effects in functional components.
Equivalent of class-based componentDidMount
: To replicate the behavior of componentDidMount
using useEffect
, you pass a function and an empty dependency array. This tells React to run the effect only once after the initial rendering, making it suitable for setups like API calls or subscriptions.
1useEffect(() => { 2 // Code here runs only after the initial render 3}, []); // Empty dependency array
Equivalent of class-based componentDidUpdate
: By including specific values in the dependency array, useEffect
will re-run the effect anytime those values change, akin to componentDidUpdate
.
1useEffect(() => { 2 // Code here runs whenever 'value' changes 3}, [value]); // Dependency array with 'value'
Equivalent of class-based componentWillUnmount
: To mimic this lifecycle method, useEffect
returns a function that will be called when the component is about to be unmounted. This is ideal for cleanup activities.
1useEffect(() => { 2 return () => { 3 // Cleanup code here runs on component unmount 4 }; 5}, []);
The useEffect
hook provides a unified and more flexible way to handle side effects compared to traditional class-based lifecycle methods, aligning with the functional programming paradigm and making code reuse and composition easier. More the the useEffect react hook
🔗 Here you can find more information about all the React JS lifecycle methods.
Class components are no longer recommended so we updated this article to remove this explanations, please use functional components instead.
Unlike class components, react functional components are simplified React components originally intended for presentational purposes. For that reason they are traditionally stateless: they have no state of their own. That allows them to be lighter, faster, and easier to write.
Functions' statelessness was addressed with React 16.8.0 which introduced the ever-so-popular React Hooks. Since then the useState
hook allows us to reproduce state behavior in our functional components:
So React Hooks effectively changed the nature of the original React functional components, and now both types of components are very similar in the things they can do. Because of that, we strongly encourage you to use functions and hooks as much as possible.
You can switch from one type of declaration to the other without any pain! Here is a comparison of both types of components:
As a Function: Very simple declaration and usage. The only purpose of the function is to return an HTML with whatever the component is supposed to display when placed on the website.
As a Class: It is more complex, the class declaration needs to inherit from React.Component and contains a lot more functionalities that let the developer customize the component logic, like life-cycle methods and the state. Please consider that you can create as many additional class methods as you like.