React Best Practices - Anoymous Functions
Psst, if you wanna skip ahead to the final code example, click here.
You shouldn't use anonymous functions as props in React. But why?
This post will cover the following:
- What is an Anonymous Function?
- Object (And Function) References
An anonymous function is a function that doesn't have a name. That's it!
It's important to understand the difference between an anonymous function and a named function. For example, take a look at this forEach method:
forEach takes a callback (function).
The callback provided to
forEach in this example is a legitimate function, but it does not have a name.
The code above is essentially the same as this:
While the functions in both examples are identical in the tasks performed, there is one significant difference: in
the second example, the callback function has a name,
One of the benefits of the
logItem function is that, as a named function, it can be called anywhere within this scope. It is impossible to reuse anonymous functions.
If I had used an anonymous function as a callback to
forEach on line 3, then I wouldn't be able to call
logItem on line 11!
Think of anonymous functions like renting a car instead of buying.
Imagine if you didn't own a car. Every time you needed to drive, you would have to find a ride to a car rental lot and fill out a bunch of paperwork before you could finally go about your errands. This model makes sense in some cases, like when you need a moving truck, because the vehicle you're renting doesn't fit your daily needs. But most people would find it unreasonable to have to visit a car rental lot everyday prior to driving to work. Buying makes the most sense in this case.
Similarly, there will be some cases where creating a named function is more overhead with no added benefit. Renting, or using an anonymous function, makes the most sense in these instances. But in most scenarios, you'll be surprised how reusable your functions can be.
Are you renting functions when you should be buying?
...Wait, what? Let's break this down a little bit.
Before we dive into what objects are, we need to talk a little bit about what they are not. Objects are non-primitive.
According to MDN, a primitive is data that is not an object and has no methods. There are 6 primitive data types in JS:
Variables of a primitive data type are assigned a
value. Each additional assignment provides a new value. The following code example demonstrates how new values are assigned:
When I called
incrementNumber, a new value was created by combining the values of
n (27) and 1 to make a new primitive value, 28. The original value in the
number variable doesn't mutate.
There are 4 non-primitive data types in JS:
*Null is a unique case, because every Object is derived from
Variables of a primitive data type are assigned a
reference. Each additional assignment mutates the original data.
Let's look at another code example:
If you make a change to a non-primitive type, that change will be applied to every instance of that object. This is because, unlike primitive types, a new object isn't being created every time you assign a variable to the object.
With non-primitives, the variable is told where in the computer's memory that data can be found. The variable will access the data, make necessary use of it, and then put it back where it belongs.
To create a unique reference for an object, destructure its values to create a copy before assiging to a variable:
Since I destructured the original object when creating the
objectForFunction variable, the new object's property values were created with the primitive values of each property in the original object. In other words, instead of creating a reference to the original object, a new object was created with the same properties.
Given that an object gets mutated when you make changes to it, it isn't even necessary for the function to return your object. In fact, I've stopped doing this in a lot of my code so that it's easier for me to remember when I'm working with a reference instead of a value:
The single instance of
newObject living in memory gets mutated. No return needed.
Now that we understand anonymous functions and non-pimitive types, let's take a closer look at functions.
Non-primitive data can be referenced using its name. Because anonymous functions don't have a name, there is no way for the computer to know if two functions are identical.
To create a reference to a function, you must assign it to a variable:
Having covered vanilla JS first, there isn't much to talk about specific to React.
Let's review what we've learned so far:
- Anonymous functions are functions that do not have a name and can't be reused
- There are two data types in JS, primitive and non-primitive
- Primitive variables have a value, non-primitive variables have a reference
- Mutating a non-primitive mutates it for all references
- You cannot reference anonymous functions, because non-primitives are referenced by their name
Combining these topics, one can conclude that anonymous functions can be dangerous as React props.
Using an anonymous function as a prop looks something like this:
Without a reference to compare,
MyOtherComponent has no choice but to re-render, because as far as it can tell, it just received a new prop. Depending on what's happening each time you render
MyOtherComponent, this can become very expensive!
There is an important detail in this code example you won't want to miss.
Not only am I supplying a named function as a prop, I am placing the callback outside of the scope of my component function.
Reference is relative to scope. In other words, if
myCallback had been inside the closure of
MyComponent, a new reference would be created each time
MyComponent re-renders. We might as well keep an anonymous function in that case!
Like many concepts in React, the best way to learn is to learn more about JS itself.
This is an intermediate subject. If you are a new developer and found any of this discouraging, continue to learn. Reference (pun intended) this post periodically, and see if it becomes easier to understand over time. I doubt a question like this would come up in interviews for junior positions.
Thanks for reading!
Subscribe to be the first to get the latest from Leo!
Share This Article
About the Author: Leo Yockey
Leo Yockey (he/him/his) is the Founder of MangoBass Consulting. He is also a co-founder of Hackertunity and an advocate for underrepresented technologists. If you enjoy his writing, you can see more on his personal blog or twitter.