Words out: with the react the new characteristics of HOOKS, the inside of the latest lot of people are beginning to discuss the react function components and the class what’s different? How Are Function Components Different From Classes by Dan Abramov How Are Function Components Different From Classes

How is the React function component different from the React class?

For a while, the canonical answer was that classes provided more functionality (such as state). Hooks are no longer so true.

Maybe you’ve heard that one of them has better performance. Which one is that? Many of the arguments based on this are flawed, so I would be careful to draw conclusions from them. Performance depends primarily on what the code does, not whether you choose a function or a class. In our observation, although the optimization strategy was slightly different, the performance difference was negligible.

In either case, we do not recommend using HOOKS to rewrite existing components unless you have some other reason or don’t mind being the first to use it. Hooks are still new (just like React in 2014), and some “best practices” are not yet covered in the tutorial.

So what are we going to do? Are there any fundamental differences between React functions and classes? And, of course, in mental models. In this article, I’ll look at the biggest differences between them. The function component has been around since it was introduced in 2015, but is often overlooked:

The function component captures rendered values.

Let’s see what that means.


Note: This article is not focused on evaluating classes or functions. I’ll just illustrate the differences between the two syntax models in React. Refer to the broader adoption of functional componentsHooks FQA


Consider this component:

function ProfilePage(props) {
  const showMessage = (a)= > {
    alert('Followed ' + props.user);
  };

  const handleClick = (a)= > {
    setTimeout(showMessage, 3000);
  };

  return (
    <button onClick={handleClick}>Follow</button>
  );
}
Copy the code

It displays a button that simulates a network request using setTimeout, and then displays a confirmation warning popup. For example, if props. User is ‘Dan’, then calling this function 3s will show ‘Followed Dan’, which makes sense.

(Note that in this example it is ok to use arrow functions or function declarations; function handleClick() works in exactly the same way.)

How do we write this as a class? A simple transformation might look like this:

class ProfilePage extends React.Component {
  showMessage = (a)= > {
    alert('Followed ' + this.props.user);
  };

  handleClick = (a)= > {
    setTimeout(this.showMessage, 3000);
  };

  render() {
    return <button onClick={this.handleClick}>Follow</button>; }}Copy the code

It is common to think of these two snippets as equivalent. People often use these patterns in random refactorings without noticing what they mean.

However, there are some subtle differences between the two code snippets

As a reminder, if you want to figure it out for yourself, this is an online example, and the rest of this article explains the difference and its importance.


Before we begin, I want to stress that the differences I’ve described have nothing to do with React Hooks per se. The above example doesn’t even use Hooks!

It’s just the difference between functions and classes in React. If you plan to use functional components more frequently in React applications, you might want to know about it.


We’ll illustrate the differences with common bugs found in React applications.

Open the sample sandbox using an instant Profile selector and the two ProfilePage implementations above – each implementing a Follow button.

Try the following sequence of actions with two buttons:

  • Click one of the Follow buttons.
  • Change the selected configuration within 3 seconds.
  • Read the warning text

You’ll notice a difference in their results:

  • In the function basedProfilePageOn, click follow Dan configuration, then change the configuration to Sophie, 3s warning is still'Followed Dan'.
  • In class-basedProfilePageOn, a warning will be given'Followed Sophie'


In this case, the first one is behaving correctly. If I follow one person and navigate to another’s configuration, my components should not be confused about who I am following. The implementation of this class is clearly wrong.

(Although you may want to follow Sophie)


Why is this the case when we use classes?

Let’s take a closer look at the showMessage method in our class.

class ProfilePage extends React.Component {
  showMessage = (a)= > {
    alert('Followed ' + this.props.user);
  };
Copy the code

This class method reads this.props. User. Props is immutable in React so it never changes, but this is always mutable.

In fact, that’s the whole point of having this in a class. React itself changes over time so that you can read new versions in Render and lifecycle functions.

So if our component is updated when the request is run. This.props will change. The showMessage method reads user from the “latest” props.

This is an interesting revelation about the nature of user interfaces. If we say that the UI is conceptually a function of the current application state, then the event handlers are part of the rendered output, just like the visual output. Our event handler “belongs” to a particular render with a particular props and state.

But this rule is broken when the timer callback reads this.props. Our showMessage callback is not bound to any particular render, so it loses the correct props, and reading props from this breaks the connection.


Suppose the function component does not exist, how do we solve this problem?

We want to somehow “fix” the connection between props and the showMessage callback that reads them after rendering. Because Props lost the proper meaning in passing.

One way is to read this.props at the beginning of the event handler and pass it exactly to the setTimeout callback.

class ProfilePage extends React.Component {
  showMessage = (user) = > {
    alert('Followed ' + user);
  };

  handleClick = (a)= > {
    const {user} = this.props;
    setTimeout((a)= > this.showMessage(user), 3000);
  };

  render() {
    return <button onClick={this.handleClick}>Follow</button>; }}Copy the code

It works. However, this approach makes the code more verbose and error-prone over time. What if we need more than one prop? What if we also need to access the state? If showMessage calls another method and that method reads this.props. Something or this.state. Something, we’ll have exactly the same problem again. So we have to pass this.props and this.state as arguments to each method called by showMessage.

Not only does this go against what we normally think of as a class, it’s also extremely difficult to document and implement, and the code inevitably bugs as a result.

Again, the Alert code in handleClick does not solve the larger problem. We wanted to structure our code in a way that could be split into multiple methods, while also reading the parameters and states corresponding to them when called. This problem isn’t even unique to React — you can put data into mutable objects like this to reproduce it in any UI library.

Maybe we can bind methods in constructors?

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 <button onClick={this.handleClick}>Follow</button>; }}Copy the code

But that’s not going to fix anything. Remember, the problem was that we read this.props too late, not the syntax we were using. We can solve this problem entirely by relying on JavaScript closures

Closures are often avoided because it’s hard to understand how values change throughout the process. But in React, props and state are immutable (at least that’s highly recommended). This eliminates a major problem when using closures.

This means that if you mask props or state from a particular render, you can assume that they remain exactly the same:

class ProfilePage extends React.Component {
  render() {
    // Capture the props!
    const props = this.props;

    // Note: we are *inside render*.
    // These aren't class methods.
    const showMessage = (a)= > {
      alert('Followed ' + props.user);
    };

    const handleClick = (a)= > {
      setTimeout(showMessage, 3000);
    };

    return <button onClick={handleClick}>Follow</button>; }}Copy the code

You can get props at render time.

This way, any code inside this particular render function (including showMessage) is guaranteed to get the correct props. React will no longer “move our cheese”.

We can then add as many helper functions as we want, all of which use the captured props and state. Thanks to the help of closures!


The above example is correct but seems a little strange, what’s the point of using classes if you define functions in Render instead of using classes?

In fact, we can simplify the code by removing the class “shell” that surrounds it:

function ProfilePage(props) {
  const showMessage = (a)= > {
    alert('Followed ' + props.user);
  };

  const handleClick = (a)= > {
    setTimeout(showMessage, 3000);
  };

  return (
    <button onClick={handleClick}>Follow</button>
  );
}
Copy the code

As above, prop is still captured. React passes them in as arguments. Unlike this, the props object itself is never changed by React.

This is especially true if you deconstruct the props assignment during the function definition

function ProfilePage({ user }) {
  const showMessage = (a)= > {
    alert('Followed ' + user);
  };

  const handleClick = (a)= > {
    setTimeout(showMessage, 3000);
  };

  return (
    <button onClick={handleClick}>Follow</button>
  );
}
Copy the code

When the parent component renders the ProfilePage with different props, React calls the ProfilePage function again. But the event handler we’ve clicked on “belongs” to the previous render function, and its own showMessage callback reads the user value unchanged.

This is why in the version of the function in this example, clicking follow Sophie’s configuration and then changing the configuration to sunil shows’ Followed Sophie ‘,

follow sunil


Now we understand the biggest differences between functions and classes in React:

Function components capture the rendered values.

Using Hooks, the same principle applies to state. Consider this example:

function MessageThread() {
  const [message, setMessage] = useState(' ');

  const showMessage = (a)= > {
    alert('You said: ' + message);
  };

  const handleSendClick = (a)= > {
    setTimeout(showMessage, 3000);
  };

  const handleMessageChange = (e) = > {
    setMessage(e.target.value);
  };

  return (
    <>
      <input value={message} onChange={handleMessageChange} />
      <button onClick={handleSendClick}>Send</button>
    </>
  );
}
Copy the code

(Here’s an online example)

While this is not a very good messaging application UI, it illustrates the same point: If I send a particular message, the component should not be confused about what message is actually sent. The message of this function component captures the rendered data, which is then returned by the click event handler called by the browser. So when I hit Send message is going to be set to what I typed.


So we know that functions in React capture props and state by default. But what if we want to read the latest props and state that are not part of a particular render? What if we want to read them from the future?

Inside the class, you can do this by reading this.props and this.state, because they are mutable. React changes it. In a function component, you also have a variable value that can be shared by all components, which is called “ref”.

function MyComponent() {
  const ref = useRef(null);
  // You can read or write `ref.current`.
  // ...
}
Copy the code

But you have to manage it yourself.

The ref plays the same role as the instance field. It’s an escape pod into the world of variable commands. You may be familiar with “DOM refs,” but this concept is more general. It’s just a box you can put things in.

Even though visually this. Something looks like something. Current, they express the same concept.

React doesn’t create refs for the latest props and state by default in function components. Usually, you don’t need them and waste time allocating them, but you can manually track them if you like:

function MessageThread() {
  const [message, setMessage] = useState(' ');
  const latestMessage = useRef(' ');

  const showMessage = (a)= > {
    alert('You said: ' + latestMessage.current);
  };

  const handleSendClick = (a)= > {
    setTimeout(showMessage, 3000);
  };

  const handleMessageChange = (e) = > {
    setMessage(e.target.value);
    latestMessage.current = e.target.value;
  };
Copy the code

If we read message in showMessage, we see the message when we press send, but when we read latestmessage.current, we get the latest value, Even if the value continues to be entered after we press the Send button.

You can compare the difference between these two examples. Ref is an “opt-out” scheme for rendering consistency, which can be handy in some cases.

In general, if you want to keep rendering predictable, you should avoid reading or setting refs at render time because they are mutable. But if we want to get the latest values for specific props and state, manually updating the ref can be annoying. We can update it automatically by using effect:

function MessageThread() {
  const [message, setMessage] = useState(' ');

  // Keep track of the latest value.
  const latestMessage = useRef(' ');
  useEffect((a)= > {
    latestMessage.current = message;
  });

  const showMessage = (a)= > {
    alert('You said: ' + latestMessage.current);
  };
Copy the code

Here’s an example

We did the assignment in Effect so that the ref value would only change after the DOM update, which ensures that our changes don’t break the functionality that relies on interruptible rendering. Things like Time Slicing and Suspense.

Normally we don’t need to use refs very often. It is usually better to get props and state by default. However, it comes in handy when dealing with imperative apis such as Intervals and Subscriptions. Keep in mind that you can track any value, such as: prop and state variables, entire PROP objects, and even functions.

This pattern can also be easily optimized – for example, when the useCallback identity changes frequently. However, using reducer is usually a better solution. (Subject of future blog posts!)


In this article, we looked at common bugs in classes and how closures can be used to help us fix them. However, you may have noticed that when you try to optimize Hooks by specifying an array of dependencies, you may run into bugs caused by closures that have not been updated in time. Does that mean closures are the problem? I don’t think so.

As we saw above, closures actually help us solve subtle problems that are hard to notice. Similarly, they make it much easier to write code that works correctly in concurrent mode. This is possible because the logic inside the component hides the correct props and state when rendering it.

In all the cases I’ve seen so far, the “stale closure” problem has occurred due to the mistaken assumption that “functions don’t change” or that “props are always the same.” That’s not the case, and I hope this article helps clarify that.

Functions mask the props and state they update — so their identifiers are just as important. This is not a bug, but a feature of function components. For example, for useEffect or useCallback, functions should not be excluded from the “related array.” (The correct fix is usually useReducer or the useRef solution above — we’ll explain how to choose between the two in the documentation shortly).

When we write most React code in functions, we need to adjust our intuition about optimizing code and which values change over time

As Fredrik writes:

So far, the best psychological expectation I’ve found about hooks is that “it seems like any value in the code can be changed at any time.”

Functions are no exception. It takes some time for this to become common sense in React learning materials. It needs some tweaking from the class way of thinking. But I hope this article helps you see it in a new light.

The React function always captures their values – now we know why.