Dimitar Spassov
Dimitar Spassov

Reputation: 2733

How to prevent style tags of unused React components

I think this question may expand beyond React, but I'm still not sure if React itself is responsible for the problem.

The environment is React with TypeScript. I use CSS imports in the component files, so that each component has its specific stylesheet and I presume that those styles will not be added to the <head> element until the respective component is instantiated. But it turns out that if I import a component from a file, which just reexports all of them, the styles of all the other components, which I do not use, are still added in the DOM.

Here is a simple example, let's say I have two simple components in the lib folder - Avatar and Button. They look like this (the Button is similar):

import React from 'react';

import './avatar.css';

const Avatar: React.FC = (props: any) => {
  return (
    <div className="avatar">
      {props.children}
    </div>
  );
}
export { Avatar };

Then I add index.ts to reexport the components, in order to have simple import path:

import { Avatar } from './Avatar';
import { Button } from './Button';

export { Avatar, Button };

And finally, in my AppComponent I want to use only the Button component:

import React from 'react';
import { Button } from './lib';

const App: React.FC = () => {
  return (
    <div className="App">
          <Button>example</Button>      
    </div >
  );
}

export default App;

To my surprise, in the <head> element there are <style> tags not only for the Button, but also for the Avatar. Why is this happening? Is my reexport configuration wrong?

Notice that if I import the component directly from its file - import { Button } from './lib/Button' I do not get the Avatar styles.

The example is really simple, but the real scenario is related to a React component library, which contains a lot of components with a lot of stylesheets. I want to avoid inserting so many <style> tags in the DOM, unless they are really needed.

Thank you for spending time on this!

Upvotes: 1

Views: 1410

Answers (1)

akram-adel
akram-adel

Reputation: 1070

so that each component has its specific stylesheet and I presume that those styles will not be added to the element until the respective component is instantiated

This presumption is wrong. React uses webpack to bundle its files and the way webpack works for CSS imports is that it loads all the CSS files that your project depends on and put them in the <head> element right at the beginning.


You might ask: Then how do I keep my styles separated and don't get them mixed.
There are three solutions to this

  1. A good way is to Add a CSS Modules Stylesheet
  2. Another suggestion is to make the <div> that wraps your component have a className that is the same name as the component so your component will look like this
export default class ComponentOne extends Component {
...
  render() {
    return(
      <div className="ComponentOne">
        ...
      </div
    )
  }
}

And your component CSS file will look like:

.ComponentOne div img {
  ...
}
.ComponentOne .class-one {
 ...
}

With this way, using CSS preprocessor like SASS will come in handy, so your .scss file will simply begin with:

.ComponentOne {
  ...
}
  1. Another solution is to have the styles as an object inside your component. This way the style will only be scoped to your component and will be removed when the component unmounts, but then you will lose the ability to easily create @media queries andother special effects like:hover` plus this approach is not recommended for small components that get mounted and unmounted too often because this creates a performance issue once the application gets larger

You also might ask: since all the style sheets get imported at the begging, then why don't I put all my styles in one big style sheet and not splitting them up.

Other than the fact that splitting your styles will make them easy to handle so that each component will have its separate CSS file and webpack will handle importing them, There is one other benefit:
Say you have a feature1 component which also has a feature1.css file. In the beginning, when you have feature1 imported in your main app, webpack will also import its style sheet and put it in the <head> element.
But say in the future you decided you don't want to use feature1 component anymore and you are using another feature2 component now which has its own feature2.css file. Now since no other component is importing feature1 component, webpack will also ignore importing feature1.css into the <head> element.

Upvotes: 2

Related Questions