by Anthony Ng
Deliberate Practice: What I learned from reading the classNames codebase
This is part of my plan for deliberate practice to improve as a developer. Take a look at this article to learn more.
In this article, we’ll look at a library called
classNames (here’s the GitHub repository).
classNames provides a simple API to construct class names in React. We’ll take a look at what it does, and what I learned by going through their repo.
How to use?
classNames API is very simple. They have great examples in their README.md.
You can pass string arguments like so:
classNames also accept objects as arguments. If the value of the key is falsy (false, null, undefined, 0, NaN, empty string),
classNames omits the value.
classNames also accepts arrays as arguments. Array arguments are recursively flattened and processed using the above rules. You can mix and match different types of arguments (strings, arrays, objects).
Usage with React
This package’s primary use case is to make React’s class name simpler to work with.
classNames, you might have used string manipulation to create React’s class names.
Now with the
classNames package, it would look like this:
Common mistakes: “undefined” classnames
The most common mistake I see at work using
undefined class names.
Remember that falsy values are ignored inside the
Knowing this, we can update our
classNames example to:
Different versions that you can opt into: Dedupe
There’s 2 issues that you might run into. Do you see them?
classNames provides an opt-in version of its library for us to use, called
That’s more like it. Note that
dedupe is around 5x slower than the default
classNames package. Use this only if needed.
Different versions that you can opt into: Bind
bind is another opt-in version of
classNames. It’s meant to help us when we’re using CSS modules with React. But I find that the default
classNames package does well with CSS modules.
Take a look at the README.md for more information.
It’s a best practice to use
hasOwnProperty when iterating over an Object’s keys. You can check if the key belongs to the object, or is inherited.
We would use
hasOwnProperty to get properties that belong to our created object.
Instead of using
hasOwnProperty, we can create a new Object that inherits nothing!
But this also means methods that Objects inherit, such as toString will not exist on this new object.
Awesome documentation and great tests
Take a look through the source code of
classNames. It’s littered with amazing comments and documentation.
Awesome documentation isn’t something that’s exclusive to open source projects.
Did you find a great code snippet that you used on your personal project?
Have you spent hours searching for the perfect StackOverflow answer? Include these links as comments in your code! It will save other developers (and the future you) time when figuring out what’s going on.
classNames has amazing documentation on their README.md. It has rich examples that show everything this package can do.
Documentation and comments are great. Yet, they can rot and become out of sync with what the code actually does. But tests don’t lie! Well-written tests will tell you everything that the package should be able to do and not do. If you’re new to a library, check out their tests to get a better understanding of the library.
call are great interview questions. But I rarely get to use them in the real world. Seeing it inside of the
classNames package was a nice refresher of what it does.
call basically do the same thing. It sets the
this of the calling function.
The difference comes when you want to pass in arguments into the calling function. Let’s take a look at a function that takes in arguments.
Notice the small difference here.
apply takes its arguments in an array (I remember it by remembering that
array both start with
call takes its arguments provided individually, like a normal function would.
apply to handle array arguments passed into it.
Don’t trust anything
Take a look at the code snippet below.
Why would we save the
hasOwnProperty function to a variable? This is because we have to be defensive about the arguments given. We grab the
hasOwnProperty from the
Object.prototype. Let’s take a look at why.
That makes sense. But what if someone passed us an object like this:
hasOwnProperty function from the
Object.prototype is a safer alternative.
But note that even this isn’t foolproof. The below is still possible.
I always forget about HTML entities. I always look for a fancy image, but using HTML entities are well supported and can save you an HTTP request for an image.
Before you start scouring Google Images for assets, take a look at this chart to see if it has what you need.
You don’t need to argue with your coworker any more about
for-each loops! You can settle all disputes by seeing how it performs using benchmarking tools (such as jsPerf).
classNames is downloaded and used by many, and performance is of greatest concern. Performance differences are looked at before any pull requests are accepted.
Your personal projects might not be concerned with performance. But it is good to keep performance in mind. Take a couple of minutes to play around with jsPerf and set up your own tests.
Interested in getting adding fancy badges to your README.md? Check out this great egghead tutorial by Kent C. Dodds on starting your own Open Source project. It covers often-ignored topics, such as setting up Continuous Integration, using Semantic Release, publishing to npm, and more.
git blame, follow, history
Have you ever run into a certain line of code and was curious about how it came to be? Use the
git blame feature from the Github website. It will tell you when it was written, who wrote it, and what commit it was from.
You can also view the history of a file and see how it evolved by using
git history, located right next to
git blame. Viewing all the commits shows you how a certain file evolved over time.
I recommend that you find an Open Source project that you like and use, and start contributing back to it. You can
watch a repository and get notifications whenever there are any updates. You might not be ready to push code changes. But updating documentation or helping with other people’s issues are valuable as well.
Thank you for reading this, and I hope you learned something new.