DEV Community

Cover image for My secret trick for writing great React components
Victor Ocnarescu
Victor Ocnarescu

Posted on

My secret trick for writing great React components

I have a confession to make. I do not write a single test for my React components. Yes, you read that right, not a single one. You might wonder how I keep track of complex React projects with many many components. Here's my trick:

Always write React components that you can read without scrolling.

As a rule of thumb, if you cannot read a React component without scrolling, then I bet it does more than one thing. It has more than one responsibility, more than one single purpose.

Thinking in React

The first thing you’ll want to do is to draw boxes around every component (and subcomponent) in the mock and give them all names.

This is an actual quote from the React docs that apparently everybody forgot to read.

Thinking in React

If you follow this advice every component that you write will do one and only one thing, will serve only one purpose. If it ends up growing, it should be decomposed into smaller subcomponents.

What about complex functions that manipulate data? This is also simple: I just create a pure function with all the logic, save it in a file and just use it in my React components.

Let's see some code

Let's assume I want to add React Context to one of my components.

const AwesomeComponent = (props) => {
  const defaults = {
    mode: 'dark',
  };
  const cache = {
    mode: local.get('theme.mode'),
  };
  const initialTheme = merge(defaults, cache);
  const [theme, setTheme] = useState(initialTheme);

  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      <div className="awesome-component">
        <div>everything else...</div>
      </div>
    </ThemeContext.Provider>
  );
};
Enter fullscreen mode Exit fullscreen mode

The first part of the component uses the useState React hook. It also initializes the state with some default values taken from some options cached values.

First improvement

The defaults can really grow over time to many other options, not just mode. Let's make a function that initializes the state. This function will have a single purpose: initializing the state.

const AwesomeComponent = (props) => {
  const [theme, setTheme] = useState(themable());

  return (
    <ThemeContext.Provider value={{ theme, setTheme }}>
      <div className="awesome-component">
        <div>everything else...</div>
      </div>
    </ThemeContext.Provider>
  );
};
Enter fullscreen mode Exit fullscreen mode

Second improvement

The component still does more than it should. Let's move the hard-to-read React context code in a separate component and just implement it in our main component. This way we will not care how the context is initialized, we will care only that the context WAS initialized.

const AwesomeComponent = (props) => {
  return (
    <Theme>
      <div className="awesome-component">
        <div>everything else...</div>
      </div>
    </Theme>
  );
};
Enter fullscreen mode Exit fullscreen mode

More improvements

If you start thinking this way in React you will notice these small changes everywhere in your projects. And your projects will become better and better.

Final thoughts

Code clutter

We're all guilty of it. Junior devs, senior devs, fullstack devs. We all have written God classes in OOP or huge React components without splitting them by purpose.

But this has to change, otherwise the complex project you are working on is going to become a complex monster project.

And it has to change fast. So next time you plan to write some React component, hook or just a plain function: why not split it in multiple files, each one with a single responsibility? The world of programming would be a much better place.

Top comments (19)

Collapse
 
bertmeeuws profile image
Bert Meeuws

"Always write React components that you can read without scrolling."

Tailwind has entered the chat

Collapse
 
moracabanas profile image
mrcbns • Edited

I usually create old style css name classes and @apply directive to get rid of huge inline classes.

It also let me split styling from behavioural tailwind classes on different @apply directives on the same class so mt-2 is not mixed with hover: and so on

Collapse
 
randomusername profile image
Heroe • Edited

What's even the point of using tailwind that way and not just use css/sass ?

Confession: The apply feature in Tailwind basically only exists to trick people who are put off by long lists of classes into trying the framework.
You should almost never use it 😬
Reuse your utility-littered HTML instead

from the creator himself twitter.com/adamwathan/status/1226...

Collapse
 
bertmeeuws profile image
Bert Meeuws

I am in love with tailwind, the way you can just copy paste html and pass it on to a partner and it should look the same (taking position etc. into consideration).

And never having to scroll trough massive css files is worth the hassle of big HTML.

Thread Thread
 
randomusername profile image
Heroe • Edited

Well it may be fine but tailwind didn't invent anything nor there is anything innovative into this approcah, that's just old css utility classes, a bit like bootstrap ( although you'd most likely still use custom css with it since it;s opinionated ) and almost verbatim what tachyons basscss etc have been doing for years.

Thread Thread
 
muhsarip profile image
muhsarip

too many class inside single element, make use of tailwind is harder to read.

Thread Thread
 
victorocna profile image
Victor Ocnarescu

You are perfectly right, Tailwind did not invent anything new and Tachyons did this years ago. In my personal experience I prefer Tailwind over Tachyons because class names have better names for the first one.

Take f5-l which for Tachyons means font-size: 1rem.
Tailwind has font-base which means the same thing.

Thread Thread
 
victorocna profile image
Victor Ocnarescu • Edited

I also love the fact that I do not have to come up with names for classes. In the old days I would say container or container-header, now I just add utility classes like flex flex-col gap-2 and everyone in my team understands the CSS behind it.

Collapse
 
Sloan, the sloth mascot
Comment deleted
Collapse
 
victorocna profile image
Victor Ocnarescu

Interesting article. If i understand correctly, Kent would not split a simple component that just contains many many html elements.

I disagree and would split this component right away. The worst case scenario: I have a few extra components included in my main component that are easier to read and have meaningful names.

If I may ask, how large is your largest file on the project you are working on? I am onboarding in a new project where I saw components with over 1000 lines of code. Horror!

Collapse
 
l0st0 profile image
l0st0

I guess you did not see 14000 lines of code :D believe me 1000 is not so bad at all

Collapse
 
joeattardi profile image
Joe Attardi

A 1,000+ line component sounds like a nightmare, I think that is a perfectly valid reason to break it up :)

Collapse
 
redicrafty profile image
redicrafty

This is one of the best articles I've seen on this platform. Straight to the problem with easy to understand and simple code examples, good english. Basically everything to keep the reader engaged.
Well done!

Collapse
 
victorocna profile image
Victor Ocnarescu

Thanks a lot for your feedback, it really made my day better. I'll try to do my best in the future as well. This really is the most important problem that I've noticed in React projects so I'm glad you found it useful.

Collapse
 
edpe profile image
Ed Perkins • Edited

It's a nice idea, but wading through a million nested components is a debugging nightmare and makes the context of each component difficult to understand for someone who is new to the project.

I always prefer to abstract when I need to rather than adhere to the single responsibility principle. I'm not convinced that universal rules are necessarily always useful.

Collapse
 
victorocna profile image
Victor Ocnarescu

I was not convinced at first as well, but I found out over and over again that if it's easier to read it has less bugs.

I'm curios about the abstraxtion you were referring. Could you give me an example?

Collapse
 
junnu12 profile image
MRJUNNU

File Organization. React doesn't recommend a specific pattern to organize folder structure, but there are a couple of suggestions on their website. ...
Don't Repeat Yourself. ...
Name Your Components Well. ...
Use PropTypes (or TypeScript) for Type Checking. ...
Use Linting Tools. ...
Separate Display and Business Logic. ...
Write Test Cases.
By: cinemahd-v2.com/

Collapse
 
dubesar profile image
Sarvesh Dubey

How do you write a component like modal and use for every type of modal.

Collapse
 
victorocna profile image
Victor Ocnarescu

I use a generic modal component like the modal from the react-bootstrap package and I customize it by writing new modals in separate files.

Something like this:

const ConfirmModal = ({ isOpen, hide }) => {
  return (
    <Modal centered backdrop="static" show={isOpen} onHide={hide}>
      <h2>hello world</h2>
    </Modal>
  );
};
Enter fullscreen mode Exit fullscreen mode