Fat Arrow Function Clarification in React

You are intending to delete a movie, so you are filtering for everything that doesn’t match the movie being deleted.

It’s this.state.movies.filter that results in the m variable. this.state.movies is a list where each item is a movie. The filter method passes each item (that being a movie) to the function. The function then receives that movie as the first parameter of the function. In this case, it is m that has been decided to refer to each movie in the list.

Let’s start with code that doesn’t use fat arrows.

function handleDelete(movie) {
    function movieFilter(m) {
        return m._id !== movie._id;
    }
    const movies = this.state.movies.filter(movieFilter);
    return this.setState({ movies });
}

The above functions are normal and standard function declarations. They can also be assigned to variables, where a function expression is used for that instead.

Here is the same code using function expressions. I’ve commented out the previous code, to help show how the changes occur.

// function handleDelete(movie) {
const handleDelete = function handleDelete(movie) {
    // function movieFilter(m) {
    const movieFilter = function movieFilter(m) {
        return m._id !== movie._id;
    // }
    };
    const movies = this.state.movies.filter(movieFilter);
    return this.setState({ movies });
// }
};

With function expressions, the variable and the function name can be different. Inside of the function you can refer to the function both by the function name, and the variable that you assigned the function to.

Some people prefer to make them anonymous functions by removing the function name, which removes the clutter of doubling up the function names. I have a personal and historical dislike for anonymous functions though, because when debugging it can be difficult to to see where you are in a trace report when using anonymous functions.

Still, here’s the same code with anonymous functions:

// const handleDelete = function handleDelete(movie) {
const handleDelete = function (movie) {
    // const movieFilter = function movieFilter(m) {
    const movieFilter = function (m) {
        return m._id !== movie._id;
    };
    const movies = this.state.movies.filter(movieFilter);
    return this.setState({ movies });
};

You can also use functions directly as function arguments. Terms like arguments and parameters tend to get bandied about a lot, and they have specific meanings.

The following code helps to clear up that confusion and helps to give a clear understanding about how arguments and parameters differ.

function sum(parameter1, parameter2) {
    return parameter1 + parameter2;
}
const argument1 = 3;
const argument2 = 5;
sum(argument1, argument2); // 8

Parameters are defined as part of the function declaration or function expression.
When you execute or call the function, arguments are what you give to the function, which are then received by that function as the parameters.

The movieFilter function can also be given as an argument directly to the filter function. That means that we don’t need to assign it as a variable. The function can either be named or anonymous too. I prefer to use named functions, as that can help us to better understand what the function is supposed to be doing.

const handleDelete = function (movie) {
    // const movieFilter = function (m) {
    //     return m._id !== movie._id;
    // };
    // const movies = this.state.movies.filter(movieFilter);
    const movies = this.state.movies.filter(function filterMovie(m) {
        return m._id !== movie._id;
    });
    return this.setState({ movies });
};

You can also use arrow-notation with the filterMovie variable. The simplest way to convert a function to arrow-notation, is to remove the word function, place an arrow after the parameters, and remove the return keyword.

Here is some example code with the old filterMovie function commented out, and replaced with arrow-notation instead.

    // const movieFilter = function (m) {
    //      return m._id !== movie._id;
    // };
    const movieFilter = (m) => {
         m._id !== movie._id);
    };

While arrow-notation with multiple statements is supported by using the function braces, it’s preferred to use arrow-notation as a simple one-liner expression, by removing the function braces too.

    // const movieFilter = (m) => {
    //      m._id !== movie._id;
    // };
    const movieFilter = (m) => m._id !== movie._id;

When there’s only one function parameter, you can even remove the parenthesis around the parameter, but some style guides and linters, and myself, disagree with that. Still, here’s what it looks like without the parameter parenthesis.

    // const movieFilter = (m) => m._id !== movie._id;
    const movieFilter = m => m._id !== movie._id;

Finally, the movieFilter arrow-notation function can be given to the filter method as an argument to the filter function, and is how your original code uses the arrow-notation.

const handleDelete = function (movie) {
    // const movieFilter = m => m._id !== movie._id;
    // const movies = this.state.movies.filter(movieFilter);
    const movies = this.state.movies.filter(m => m._id !== movie._id);
    return this.setState({ movies });
};

If I had my way about things, I would try to improve the understandability of the code by extracting the arrow-function out to a separate variable, retain the function parenthesis, and slightly rename some variables for better clarity.

const handleDelete = function (movieToDelete) {
    const keepMovieFilter = (movie) => movie._id !== movieToDelete._id;
    const movies = this.state.movies.filter(keepMovieFilter);
    return this.setState({ movies });
};

I hope that helps to give a better understanding of how one type of style flows into another.

9 Likes