How to emulate a “Constructor” in React Functional Component with Custom Hooks

Theodoros Mathioudakis
JavaScript in Plain English
4 min readNov 9, 2020

--

Functional components in React are missing the concept of a Constructor

But what is a Constructor?

In class-based object-oriented programming, a constructor (abbreviation: ctor) is a special type of subroutine called to create an object. It prepares the new object for use, often accepting arguments that the constructor uses to set required member variables. ~ wiki link

So, in simple words with a Constructor we initialize the state of our component, and someone could say that “Function components don’t need a constructor. You can initialise the state in the useState call.”

The problem here is that Function components are… functions. They run whenever you call them. Just like that. This means that we don’t have life-cycles, which also means that we don’t have a place in which we can actually initialize our component with a code that runs only once before the component is rendered for the first time.

A real life example of the problem.

In the following example, we have a modal with an inner form. The performance field has a validation that is in sync with the discipline. Since this form is for editing and creating, we need to know with what validation we want to initialize the form. To achieve it, we pass the validation from the parent to the component via props and handle the validation with a Hook

What we also want is to set the field values only when the component is initialised.

We have the problem that each time we call the onFocusPerformance(), the state is changing due tosetPerformanceValidation(), which leads to rerun the code block inside the red box and reset the values in the form again.

The solution

We can programmatically create a function that will be called each time the component is run BUT will execute its inner code based on a flag.
This is actually how a Singleton is implemented. We want something. If exists, bring the existing, if not create a new one. Something like this::

const OurFunctionalComponent = () => {
const [constructorHasRun, setConstructorHasRun] = useState(false);
const constructor = () => {
if (constructorHasRun) return;
// Some code...
setConstructorHasRun(true);
};
constructor(); // called on each re-render
...
}

We are now OK, but the implementation is not as clean as possible. We need to code this logic on each component we need. We can avoid it by using custom Hooks.

By moving our logic into a custom Hook, we can have a more clean “constructor”.

Note: To get the behavior of the Constructor — keep in mind — that we need to invoke it on top of the function to run it before everything.

UPDATE 1: There are some comments that point out the usage of useEffects instead of this approach.

The useEffect Hook doesn’t satisfies all conditions for a Constructor.

The useEffect is run once, and only once, for the entire life-cycle of this component. We are fine with that. We have the one part of our requirements.

The problem is that it runs *after* the component is rendered. And of course this is what we are expecting to happen since this is cleary stated in the Hooks documentation: “By default, effects run after every completed render.

UPDATE 2: As mentioned in one of the comments in this post “you’re getting into territory where you could end up with memory leaks, or code that’s brittle and breakable under future releases of React.”. Even if the purpose of this post wasn’t to propose an alternative to useEffect() (😅 Obviously), I had some experimentations and I managed to change the implementation. Now instead of my custom useConstructor hook I use the useEffect().

My initial scenario was complex and I had to refactor much more code in order to manage to have the expecting behaviour on my component. So, I leave the rest of the post untouched and I add the changed code above in order to be easy for everyone to make a comparison.

--

--