10

I have used the following code to import css

componentWillMount() {
    import('./patient-summary.css');
}

How to remove imported css from react when component is not in use. When i go back to previous screen this css gets applied there. Any idea ?

UPDATE:: Webpack config

const path = require('path');
const webpack = require('webpack');

module.exports = {
  entry: './src/index.js',
  output: {
  filename: 'bundle.js',
  path: path.resolve(__dirname, 'public/dist')
},
module: {
  rules: [
      {
          test: /\.js?$/, 
          loader: 'babel-loader',
          exclude: /node_modules/
      },
      {
          test: /\.css$/,
          use: [ 'style-loader', 'css-loader' ]
      },
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/,
        loader: "file-loader"
      }
      ,
      {
        test: /\.(png|jpeg|jpg|gif|svg)$/,
        loader: "file-loader"
      }
  ]
  },
  devServer: {
  contentBase: path.resolve(__dirname, "public"),
  historyApiFallback: true,
  port: 3000,
  watchOptions: {
    // Delay the rebuild after the first change
    aggregateTimeout: 300,

    // Poll using interval (in ms, accepts boolean too)
    poll: 1000,
  },
  },
  plugins: [
   // Ignore node_modules so CPU usage with poll
   // watching drops significantly.
   new webpack.WatchIgnorePlugin([
      path.join(__dirname, "node_modules")
   ])
 ],
 };
7
  • Please post your webpack configurations. I think you concat all css files together. Commented Jan 1, 2018 at 6:39
  • why would you want to remove the imports. they will be in the local cache. let it be there Commented Jan 1, 2018 at 8:47
  • @M.R.Safari updated Commented Jan 1, 2018 at 10:11
  • So... I guess you haven't found any solution yet Commented Dec 12, 2019 at 17:48
  • @Denny I found it. To import all css files at top of the component. Atlast in webpack build all the css into a single file. So its not individual css files. Just one file Commented Dec 14, 2019 at 14:19

2 Answers 2

6

I found a (sort of) reasonable way to do this in React. In short, you can lazy-load React components that contain the import './style.css', and when it loads, you can capture the imported StyleSheet to toggle its StyleSheet.disabled property later.

Here's the main code, with more explanation below. Here's my Gist.

useDisableImportedStyles.tsx

import { useEffect } from 'react'

// global list of all the StyleSheets that are touched in useDisableImportedStyles
const switchableGlobalStyleSheets: StyleSheet[] = []

// just to clarify what createUseDisableImportedStyles() returns
type useDisableImportedStyles = () => void

export const createUseDisableImportedStyles = (
    immediatelyUnloadStyle: boolean = true
    // if true: immediately unloads the StyleSheet when the component is unmounted
    // if false: waits to unloads the StyleSheet until another instance of useDisableImportedStyles is called.This avoids a flash of unstyled content
): useDisableImportedStyles => {
    let localStyleSheet: StyleSheet
    return () => {
        useEffect(() => {

            // if there are no stylesheets, you did something wrong...
            if (document.styleSheets.length < 1) return

            // set the localStyleSheet if this is the first time this instance of this useEffect is called
            if (localStyleSheet == null) {
                localStyleSheet = document.styleSheets[document.styleSheets.length - 1]
                switchableGlobalStyleSheets.push(localStyleSheet)
            }

            // if we are switching StyleSheets, disable all switchableGlobalStyleSheets
            if (!immediatelyUnloadStyle) {
                switchableGlobalStyleSheets.forEach(styleSheet => styleSheet.disabled = true)
            }

            // enable our StyleSheet!
            localStyleSheet.disabled = false

            // if we are NOT switching StyleSheets, disable this StyleSheet when the component is unmounted
            if (immediatelyUnloadStyle) return () => {
                if (localStyleSheet != null) localStyleSheet.disabled = true
            }

        })
    }
}

WARNING: This is pretty finicky. You must set this up exactly or there may be unintended consequences

Conditions:

  1. createUseDisableImportedStyles must called in global scope in the same tsx file as the imported css being targeted and the component to be lazy loaded
import React from 'react'
import { createUseDisableImportedStyles } from './useDisableImportedStyles'
import './global-styles.css'
const useDisableImportedStyles = createUseDisableImportedStyles()
export const CssComponent: React.FC<{}> = () => {
    useDisableImportedStyles()
    return null
}
export default CssComponent
  1. A component using this hook should be lazy loaded:
LazyCssComponent = React.lazy(() => import('./cssComponent'))
...
<React.Suspense fallback={<></>}>
    {condition && <LazyCssComponent/>}
</React.Suspense>
  1. An exception to lazy loading might be using this in a single, normal, non-lazy component so styles are loaded on first render
  • NOTE: the InitialCssComponent never needs to actually render, it just needs to be imported
  • BUT: this will only work if there is one single .css file imported globally, otherwise, I don't know what would happen
import InitialCssComponent  from './initialCssComponent'
LazyCssComponent = React.lazy(() => import('./cssComponent'))
//...
{false && <InitialCssComponent/>}
<React.Suspense fallback={<></>}>
    {condition && <LazyCssComponent/>}
</React.Suspense>

GOOD LUCK!

Sign up to request clarification or add additional context in comments.

1 Comment

Works like a charm. I had to add a loop to select the first truly local stylesheet though, some google font import kept creeping to the end of document.styleSheets.
1

First of all, AFAIK, you should not call any imports in componentWillMount. This means that every time a new component about to mount, this css will be loaded over and over. Instead, it must be placed at the beginning of your module.

The way that you avoid unnecessary css imports is to avoid unnecessary component imports. Hence, if your component is not called anywhere, then this css will not be loaded.

For routing, I think you will need to do some code splitting, but I am not sure if it is straightforward or the right way to do.

Link 1 Link 2

4 Comments

How do we avoid importing modules since we want to route
I think you will need to do some code splitting, but I am not sure if it is straightforward or the right way to do. I added two links.
Thanks for the info . I have divided the code. But if once the css is added, if i go back to previous screen, its affected with css added later onwards
This is incorrect. Imports in ES6 (and webpack) are only loaded once. You can verify this yourself in the inspector. If there are multiple selectors, they will appear in the styles panel crossed out.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.