DEV Community

Kris Grint
Kris Grint

Posted on

Making sense of closure in JavaScript with React Hooks

A closure is the combination of a function and the lexical environment within which that function was declared. MDN

What do we really mean when we talk about closure in JavaScript? Closure occurs when an inner function has access to variables scoped to the outer function, even after the outer function has returned:

const outerFunction = () => {
    const firstName = 'John';
    const secondName = 'Doe';

    const innerFunction = () => {
        console.log(`${firstName} ${secondName}`);
    };

    return innerFunction;
};

In the example above, outerFunction is comprised of two variables and a second function. When the function is run, it will return innerFunction:

const closureExample = outerFunction();
closureExample();

By assigning the returned inner function to a variable called closureExample and then executing it, we will see the values of firstName and lastName logged out to the console. This is because innerFunction has closure over outerFunction: it has access to its properties even after the function where they were scoped to has been executed.

The new Hooks API in React is a great example of closure in action. One of these hooks, useEffect(), is used to execute code after your component has finished rendering. It's similar to React's componentDidMount lifecycle method:

import React, { useEffect } from 'react';

const Header = props => {
    const { pageTitle, headerTitle } = props;

    useEffect(() => {
        document.title = headerTitle;
        return () => {
            document.title = pageTitle;
        }
    });

    return (
        <h1>{headerTitle}</h1>
    );
}

In the example above, our Header component receives two props called headerTitle and pageTitle and returns the former surrounded by h1 tags. After rendering the heading, the useEffect() hook calls a function which will also set the title of the document to headerTitle. The function passed to useEffect() itself returns a function which, when called, will change the title of the document to pageTitle.

Because the useEffect() hook will run the function passed to it after the component has returned, but the function sets the title of the document to a property scoped to that component, we can say that it has closure over the component's properties. A second instance of closure occurs when React calls the function which was itself returned from this function, which will occur after the component is unmounted from the DOM in a way similar to the componentWillUnmount lifecycle method. This final function sets the document title to the value of pageTitle, also scoped to the component which has long since returned. This pattern is a good way of 'cleaning up' after your component, as you can do things like reset values to their defaults or cancel outbound fetch requests.

For the longest time, closure in JavaScript has been more of a question to catch out developers in job interviews than a feature of the language with practical value. With React's Hooks API, it's becoming a lot easier to see examples of this concept in the wild.

Top comments (0)