
How are functional React components different from class-based components?
- Transfer
How are functional React components different from class-based components? For quite some time now, the traditional answer to this question is: “The use of classes allows you to use a large number of features of components, for example, state.” Now, with the advent of hooks , this answer no longer reflects the true state of affairs.
You may have heard that one of these types of components has better performance than the other. But which one? Most of the benchmarks that test this have flaws , so I would draw conclusionsbased on their results, with great care. Performance mainly depends on what is happening in the code, and not on whether functional components or class-based components are chosen to implement certain capabilities. Our study showed that the difference in performance between different types of components is negligible. However, it should be noted that the optimization strategies used to work with them differ slightly . In any case, I do not recommend

rewrite existing components with the use of new technologies if there is no good reason for that, and if you do not mind being among those who started using these technologies before everyone else. Hooks are still a new technology (the same as the React library was in 2014), and some “best practices” for their application have not yet been included in the React manuals.
Where did we finally come to? Are there any fundamental differences between the functional components of React and the components based on classes? Of course, there are such differences. These are differences in the mental model of using such components. In this article I will consider their most serious difference. It has existed since, in 2015, functional components appeared, but it is often overlooked. It consists in the fact that functional components capture rendered values. Let's talk about what that really means.
It should be noted that this material does not constitute an attempt to evaluate components of different types. I just describe the difference between the two programming models in React. If you want to know more about the use of functional components in the light of innovations, refer to this list of questions and answers on hooks.
Consider this component:
It displays a button that, by pressing a function
Note that it doesn't matter if arrow functions or function declarations are used here. View design
How to rewrite this component as a class? If you just redo the code just examined, converting it to the code of a component based on a class, you get the following:
It is generally accepted that two such code fragments are equivalent. And developers are often completely free, in the course of code refactoring, transform one into another, without thinking about the possible consequences.

These code snippets seem to be equivalent.
However, there is a slight difference between these code snippets. Take a closer look at them. See the difference? For example, I did not see her right away.
Next, we consider the difference, so here , for anyone who wants to understand what was going on myself, a working example of this code.
Before we continue, I would like to emphasize that the difference in question has nothing to do with React hooks. In the previous examples, by the way, hooks are not even used. It's about the difference between functions and classes in React. And if you plan to use many functional components in your React applications, then you might want to understand this difference.
As a matter of fact, we will illustrate the difference between functions and classes by the example of an error that is often encountered in React applications.
Open the example page , which displays a list that allows you to select user profiles, and two buttons
Try, for each of these buttons, to perform the following sequence of actions:
Having done this, you will notice the following features:

Features of the class-based component
In this example, the behavior of the functional component is correct. If I subscribed to someone’s profile, and then switched to another profile, my component should not doubt whose profile I subscribed to. Obviously, the implementation of the mechanism in question based on the use of classes contains an error (by the way, you should definitely become a subscriber to Sofia ).
Why does a class-based component behave this way? In order to understand this, let's take a look at the method
This method reads data from
In fact, the purpose of having
As a result, if our component re-renders during the execution of the request, it
This allows you to make an interesting observation regarding user interfaces. If we say that the user interface, conceptually, is a function of the current state of the application, then the event handlers are part of the rendering results - just like the visible rendering results. Our event handlers “belong” to a specific rendering operation along with specific properties and state.
However, scheduling a timeout whose callback is reading
Imagine that there are no functional components in React. How then to solve this problem?
We need some mechanism that allows us to “restore” the connection between the method
One way to do this is to read
This approach is working . But the additional constructions used here, over time, will lead to an increase in the volume of the code and to the fact that the likelihood of errors in it will increase. What if we need more than a single property? What if we also need to work with the state? If the method
If it’s true to do so, it will destroy all the conveniences that the use of components based on classes gives. It is difficult to remember that working with methods in this way is difficult, it is difficult to automate, as a result, developers often, instead of using similar methods, agree that there are errors in their projects.
Similarly, embedding code
Maybe in order to solve this problem, you can bind methods to
But this does not solve our problem. Remember that it is that we are reading data from
Developers often try to avoid closures, as it is not easy to think about values that, over time, cannot mutate. But the properties in React are immutable! (Or, at a minimum, this is highly recommended). This allows you to stop perceiving closures as something because of which the programmer can, as they say, “shoot himself in the foot”.
This means that if you “lock” the properties or state of a particular rendering operation in the closure, you can always count on them not to change.
As you can see, here we “captured” the properties during the method call

Properties are captured when calling render
With this approach, any code that is in a method
In the method,
What we just arrived at allows us to solve the problem , but such code looks strange. Why is a class needed at all if functions are declared inside a method
We, in fact, can simplify this code by getting rid of the “shell” in the form of a class that surrounds it:
Here, as in the previous example, the properties are captured in the function, since React passes them to it as an argument. In contrast
This becomes a little more obvious if you destructure the
When the parent component renders
That is why in the original version of our example, when working with a functional component, selecting another profile after clicking on the corresponding button before the message is displayed does not change anything. If a profile was selected before clicking on the button

Using a functional component
This behavior is correct (you may also want to subscribe to Sunil by the way ).
Now we have figured out what the big difference is between functions and classes in React. As already mentioned, we are talking about the fact that functional components capture values. Now let's talk about hooks.
When using hooks, the principle of "capturing values" extends to the state. Consider the following example:
→ Here you can experiment with it.
Although this is not a model example of a messaging application interface, this project illustrates the same idea: if a user sent a message, the component should not be confused about which message was sent. The constant of
We know that functional components in React, by default, capture properties and state. But what if we need to read the latest data from properties or states that do not belong to a particular function call? What if we want to “ read them from the future ”?
In class-based components, this could be done simply by referring to
However, the programmer needs to manage such values independently.
An entity
Even externally, the view structure
By default, React does not create entities in functional components.
If we read
You can compare this and this examples in order to independently evaluate the difference. Value
In general, you should avoid reading or writing values.
→ Here is an example in which this code is used.
We assign the value inside the effect, as a result, the value
Using a value
This pattern, in addition, may be useful for optimization purposes. For example, when something seems to
In this article, we looked at one of the wrong patterns for using class-based components and talked about how to solve this problem with closures. However, you may notice that when you try to optimize hooks by specifying an array of dependencies, you may encounter errors related to obsolete closures. Does this mean that the faults themselves are a problem. I do not think so.
As shown above, closures, in fact, help us fix small problems that are difficult to notice. They, likewise, make it easier to write code that works correctly in parallel . This is possible due to the fact that inside the component the correct properties and state with which this component was rendered are “locked”.
In all the cases that I have seen so far, the problem of “obsolete closures” occurred due to the erroneous assumption that “functions do not change”, or that “properties always remain the same”. I hope that after reading this material, you are convinced that this is not so.
Functions “capture” their properties and state - and therefore understanding which functions are in question is also important. This is not a mistake; it is a feature of functional components. Functions should not be excluded from the "array of dependencies" for
If most of the code in our applications will be based on functional components, this means that we need to know more about code optimization , and what values may change over time .
Here is a good statement on this subject: “The best mental rule that applies to hooks that I have discovered is that you need to program as if any value could change at any time.”
Working with functional components is no exception to this rule. It would take some time for this to be seen in React manuals as something completely obvious. For this, it is necessary that those who had previously “thought of the classes” would slightly change their thinking style. I hope this material has helped you take a fresh look at the functional components of React.
Functional components have always captured their meanings, and now you know why this is so.

Functions in React is a Different Pokemon

You may have heard that one of these types of components has better performance than the other. But which one? Most of the benchmarks that test this have flaws , so I would draw conclusionsbased on their results, with great care. Performance mainly depends on what is happening in the code, and not on whether functional components or class-based components are chosen to implement certain capabilities. Our study showed that the difference in performance between different types of components is negligible. However, it should be noted that the optimization strategies used to work with them differ slightly . In any case, I do not recommend

rewrite existing components with the use of new technologies if there is no good reason for that, and if you do not mind being among those who started using these technologies before everyone else. Hooks are still a new technology (the same as the React library was in 2014), and some “best practices” for their application have not yet been included in the React manuals.
Where did we finally come to? Are there any fundamental differences between the functional components of React and the components based on classes? Of course, there are such differences. These are differences in the mental model of using such components. In this article I will consider their most serious difference. It has existed since, in 2015, functional components appeared, but it is often overlooked. It consists in the fact that functional components capture rendered values. Let's talk about what that really means.
It should be noted that this material does not constitute an attempt to evaluate components of different types. I just describe the difference between the two programming models in React. If you want to know more about the use of functional components in the light of innovations, refer to this list of questions and answers on hooks.
What are the features of the code of components based on functions and on classes?
Consider this component:
function ProfilePage(props) {
const showMessage = () => {
alert('Followed ' + props.user);
};
const handleClick = () => {
setTimeout(showMessage, 3000);
};
return (
);
}
It displays a button that, by pressing a function
setTimeout
, imitates a network request, and then displays a message box confirming the operation. For example, if it is props.user
stored 'Dan'
, then in the message window, after three seconds, it will be displayed 'Followed Dan'
. Note that it doesn't matter if arrow functions or function declarations are used here. View design
function handleClick()
will work the same way. How to rewrite this component as a class? If you just redo the code just examined, converting it to the code of a component based on a class, you get the following:
class ProfilePage extends React.Component {
showMessage = () => {
alert('Followed ' + this.props.user);
};
handleClick = () => {
setTimeout(this.showMessage, 3000);
};
render() {
return ;
}
}
It is generally accepted that two such code fragments are equivalent. And developers are often completely free, in the course of code refactoring, transform one into another, without thinking about the possible consequences.

These code snippets seem to be equivalent.
However, there is a slight difference between these code snippets. Take a closer look at them. See the difference? For example, I did not see her right away.
Next, we consider the difference, so here , for anyone who wants to understand what was going on myself, a working example of this code.
Before we continue, I would like to emphasize that the difference in question has nothing to do with React hooks. In the previous examples, by the way, hooks are not even used. It's about the difference between functions and classes in React. And if you plan to use many functional components in your React applications, then you might want to understand this difference.
As a matter of fact, we will illustrate the difference between functions and classes by the example of an error that is often encountered in React applications.
The error that is common in React applications.
Open the example page , which displays a list that allows you to select user profiles, and two buttons
Follow
that are displayed by the components ProfilePageFunction
and ProfilePageClass
, functional, and based on the class, the code of which is shown above. Try, for each of these buttons, to perform the following sequence of actions:
- Click on the button.
- Change the selected profile before 3 seconds elapse after clicking on the button.
- Read the text displayed in the message box.
Having done this, you will notice the following features:
- When you click on the button formed by the functional component, with the selected profile
Dan
and the subsequent switching to the profileSophie
, a message box will be displayed'Followed Dan'
. - If you do the same with a button formed by a component based on a class, it will be displayed
'Followed Sophie'
.

Features of the class-based component
In this example, the behavior of the functional component is correct. If I subscribed to someone’s profile, and then switched to another profile, my component should not doubt whose profile I subscribed to. Obviously, the implementation of the mechanism in question based on the use of classes contains an error (by the way, you should definitely become a subscriber to Sofia ).
Causes of Class-Based Component Malfunctioning
Why does a class-based component behave this way? In order to understand this, let's take a look at the method
showMessage
in our class:class ProfilePage extends React.Component {
showMessage = () => {
alert('Followed ' + this.props.user);
};
This method reads data from
this.props.user
. Properties in React are immutable, so they do not change. However this
, as always, it is a mutable entity. In fact, the purpose of having
this
a class is to be able this
to change. The React library itself periodically performs mutations this
, which allows working with the latest versions of the method render
and methods of the component life cycle. As a result, if our component re-renders during the execution of the request, it
this.props
will change. After that, the method will showMessage
read the value user
from the "too new" entity props
.This allows you to make an interesting observation regarding user interfaces. If we say that the user interface, conceptually, is a function of the current state of the application, then the event handlers are part of the rendering results - just like the visible rendering results. Our event handlers “belong” to a specific rendering operation along with specific properties and state.
However, scheduling a timeout whose callback is reading
this.props
violates this connection. The callback is showMessage
not “tied” to any particular rendering operation, as a result, it “loses” the correct properties. Reading data from this
breaks this connection.How, by means of class-based components, to solve the problem?
Imagine that there are no functional components in React. How then to solve this problem?
We need some mechanism that allows us to “restore” the connection between the method
render
with the correct properties and the callback showMessage
that reads data from the properties. This mechanism should be located somewhere where the entity props
with the correct data is lost . One way to do this is to read
this.props
the events in advance in the event handler, and then explicitly pass what was read to the callback function used in setTimeout
:class ProfilePage extends React.Component {
showMessage = (user) => {
alert('Followed ' + user);
};
handleClick = () => {
const {user} = this.props;
setTimeout(() => this.showMessage(user), 3000);
};
render() {
return ;
}
}
This approach is working . But the additional constructions used here, over time, will lead to an increase in the volume of the code and to the fact that the likelihood of errors in it will increase. What if we need more than a single property? What if we also need to work with the state? If the method
showMessage
calls another method and this method reads this.props.something
or this.state.something
, then we will again encounter the same problem. And in order to solve it, we would have to pass this.props
, and this.state
as arguments to all methods that are called out showMessage
.If it’s true to do so, it will destroy all the conveniences that the use of components based on classes gives. It is difficult to remember that working with methods in this way is difficult, it is difficult to automate, as a result, developers often, instead of using similar methods, agree that there are errors in their projects.
Similarly, embedding code
alert
inhandleClick
does not solve a more global problem. We need to structure the code so that it can be divided into many methods, but also so that we can read the properties and state that correspond to the rendering operation associated with a particular call. This problem, by the way, does not even apply exclusively to React. You can play it in any library for developing user interfaces, which puts data in mutable objects like this
. Maybe in order to solve this problem, you can bind methods to
this
in the constructor?class ProfilePage extends React.Component {
constructor(props) {
super(props);
this.showMessage = this.showMessage.bind(this);
this.handleClick = this.handleClick.bind(this);
}
showMessage() {
alert('Followed ' + this.props.user);
}
handleClick() {
setTimeout(this.showMessage, 3000);
}
render() {
return ;
}
}
But this does not solve our problem. Remember that it is that we are reading data from
this.props
too late, and not in the syntax used! However, this problem will be resolved if we rely on JavaScript closures. Developers often try to avoid closures, as it is not easy to think about values that, over time, cannot mutate. But the properties in React are immutable! (Or, at a minimum, this is highly recommended). This allows you to stop perceiving closures as something because of which the programmer can, as they say, “shoot himself in the foot”.
This means that if you “lock” the properties or state of a particular rendering operation in the closure, you can always count on them not to change.
class ProfilePage extends React.Component {
render() {
// Захватываем свойства!
const props = this.props;
// Обратите внимание на то, что мы находимся внутри метода render.
// Эти функции - не методы класса.
const showMessage = () => {
alert('Followed ' + props.user);
};
const handleClick = () => {
setTimeout(showMessage, 3000);
};
return ;
}
}
As you can see, here we “captured” the properties during the method call
render
.
Properties are captured when calling render
With this approach, any code that is in a method
render
(including showMessage
) is guaranteed to see properties captured during a specific call to this method. As a result, React will no longer be able to stop us from doing what we need. In the method,
render
you can describe as many auxiliary functions as you like and all of them will be able to use the "captured" properties and state. This is how closures solved our problem.Analysis of the solution to the problem using closure
What we just arrived at allows us to solve the problem , but such code looks strange. Why is a class needed at all if functions are declared inside a method
render
, and not as class methods? We, in fact, can simplify this code by getting rid of the “shell” in the form of a class that surrounds it:
function ProfilePage(props) {
const showMessage = () => {
alert('Followed ' + props.user);
};
const handleClick = () => {
setTimeout(showMessage, 3000);
};
return (
);
}
Here, as in the previous example, the properties are captured in the function, since React passes them to it as an argument. In contrast
this
, React never performs mutations on an object props
. This becomes a little more obvious if you destructure the
props
function declaration:function ProfilePage({ user }) {
const showMessage = () => {
alert('Followed ' + user);
};
const handleClick = () => {
setTimeout(showMessage, 3000);
};
return (
);
}
When the parent component renders
ProfilePage
with other properties, React will call the function again ProfilePage
. But the event handler that has already been called “belongs” to the previous call to this function, this call uses its own value user
and its own callback showMessage
, which reads this value. All this remains untouched. That is why in the original version of our example, when working with a functional component, selecting another profile after clicking on the corresponding button before the message is displayed does not change anything. If a profile was selected before clicking on the button
Sophie
, then in the message window, no matter what happens, it will be displayed 'Followed Sophie'
.
Using a functional component
This behavior is correct (you may also want to subscribe to Sunil by the way ).
Now we have figured out what the big difference is between functions and classes in React. As already mentioned, we are talking about the fact that functional components capture values. Now let's talk about hooks.
Hooks
When using hooks, the principle of "capturing values" extends to the state. Consider the following example:
function MessageThread() {
const [message, setMessage] = useState('');
const showMessage = () => {
alert('You said: ' + message);
};
const handleSendClick = () => {
setTimeout(showMessage, 3000);
};
const handleMessageChange = (e) => {
setMessage(e.target.value);
};
return (
<>
);
}
→ Here you can experiment with it.
Although this is not a model example of a messaging application interface, this project illustrates the same idea: if a user sent a message, the component should not be confused about which message was sent. The constant of
message
this functional component captures the state that “belongs” to the fact that it renders the component that gives the browser the handler for clicking the button that it calls. As a result message
, what was in the input field at the time the button was clicked is stored Send
.The problem of capturing properties and states by functional components
We know that functional components in React, by default, capture properties and state. But what if we need to read the latest data from properties or states that do not belong to a particular function call? What if we want to “ read them from the future ”?
In class-based components, this could be done simply by referring to
this.props
or this.state
, since it this
is a mutable entity. Her change is engaged in React. Functional components can also work with mutable values that are shared by all components. These values are called ref
:function MyComponent() {
const ref = useRef(null);
// Можно считывать и записывать `ref.current`.
// ...
}
However, the programmer needs to manage such values independently.
An entity
ref
plays the same role as fields of an instance of a class. This is an “emergency exit” into a mutable imperative world. You may be familiar with the concept of DOM refs, but this idea is much more general. It can be compared to a box in which a programmer can put something. Even externally, the view structure
this.something
looks like a mirror image of the structure something.current
. They are a representation of the same concept. By default, React does not create entities in functional components.
ref
for the most recent property or state values. In many cases, you will not need them, and their automatic creation would be a waste of time. However, work with them, if necessary, can be organized on their own:function MessageThread() {
const [message, setMessage] = useState('');
const latestMessage = useRef('');
const showMessage = () => {
alert('You said: ' + latestMessage.current);
};
const handleSendClick = () => {
setTimeout(showMessage, 3000);
};
const handleMessageChange = (e) => {
setMessage(e.target.value);
latestMessage.current = e.target.value;
};
If we read
message
in showMessage
, then we will see the message that was in the field at the time of pressing the button Send
. But if you read it latestMessage.current
, you can get the most recent value - even if we continue to enter text in the field after clicking on the button Send
. You can compare this and this examples in order to independently evaluate the difference. Value
ref
is a way of “avoiding” uniformity of rendering, in some cases it can be very helpful. In general, you should avoid reading or writing values.
ref
in the rendering process due to the fact that these values are mutable. We strive to make rendering predictable. However, if we need to get the freshest value of something stored in properties or in state, manually updating the value ref
can be a tedious task. It can be automated using the effect:function MessageThread() {
const [message, setMessage] = useState('');
// Отслеживаем самое свежее значение.
const latestMessage = useRef('');
useEffect(() => {
latestMessage.current = message;
});
const showMessage = () => {
alert('You said: ' + latestMessage.current);
};
→ Here is an example in which this code is used.
We assign the value inside the effect, as a result, the value
ref
changes only after the DOM is updated. This ensures that our mutation does not disrupt features like Time Slicing and Suspense , which rely on the continuity of rendering operations. Using a value
ref
in this way is not often required. Capturing properties or states usually appears to be a much better pattern of standard system behavior. However, this can be convenient when working with imperative APIs.like those using intervals or subscriptions. Remember that you can work this way with any value - with properties, with variables stored in state, with the whole object props
or even with a function. This pattern, in addition, may be useful for optimization purposes. For example, when something seems to
useCallback
change too often. True, the preferred solution is often to use a reducer .Summary
In this article, we looked at one of the wrong patterns for using class-based components and talked about how to solve this problem with closures. However, you may notice that when you try to optimize hooks by specifying an array of dependencies, you may encounter errors related to obsolete closures. Does this mean that the faults themselves are a problem. I do not think so.
As shown above, closures, in fact, help us fix small problems that are difficult to notice. They, likewise, make it easier to write code that works correctly in parallel . This is possible due to the fact that inside the component the correct properties and state with which this component was rendered are “locked”.
In all the cases that I have seen so far, the problem of “obsolete closures” occurred due to the erroneous assumption that “functions do not change”, or that “properties always remain the same”. I hope that after reading this material, you are convinced that this is not so.
Functions “capture” their properties and state - and therefore understanding which functions are in question is also important. This is not a mistake; it is a feature of functional components. Functions should not be excluded from the "array of dependencies" for
useEffect
or useCalback
, for example. (A suitable tool for solving the problem is usually either useReducer
or useRef
. We talked about this above, soon we will prepare materials that are dedicated to the choice of this or that approach).If most of the code in our applications will be based on functional components, this means that we need to know more about code optimization , and what values may change over time .
Here is a good statement on this subject: “The best mental rule that applies to hooks that I have discovered is that you need to program as if any value could change at any time.”
Working with functional components is no exception to this rule. It would take some time for this to be seen in React manuals as something completely obvious. For this, it is necessary that those who had previously “thought of the classes” would slightly change their thinking style. I hope this material has helped you take a fresh look at the functional components of React.
Functional components have always captured their meanings, and now you know why this is so.

Functions in React is a Different Pokemon
