Use CSS Modules instead of inlining styles in React
Inline css rules seem to be taking over the react world — and for good reason. I can colocate my component styles and jsx and avoid class names that are global. Plenty of advantages of using css rules. Excellent presentation on this talk here — https://speakerdeck.com/vjeux/react-css-in-js
Inline css can have performance implications — which may not be of much consequence most of the times, but it is good to be aware of them nonetheless. I created 10,000 divs that would alternate their background colours between red and blue every second. Obviously, this is not a real life scenario but it helps in comparing the two approaches of using css classes vs using javascript objects to pass in css rules to style the component.
This is what we are building —
React Component with Css Classes —
import React from 'react'let numBoxes = 10000;export class StyleClass extends React.Component {
constructor(props) {
super(props);
} renderBoxes() {
let boxes = [];
for(var i = 0; i < numBoxes; i++) {
boxes.push(
<div key={i}
className={`box ${this.props.toggle ? 'red' : 'blue'}`}>
</div>
)
} return boxes;
} render() {
return (
<div className="container">
{this.renderBoxes()}
</div>
)
}
}
React Component with Inline CSS Rules
import React from 'react'let blue = {'backgroundColor': 'blue'}
let red = {'backgroundColor': 'red'}
let box = {
'height': '50px',
'width': '50px', 'border': '1px solid white'
}let container = {
'height': '100vh',
'width': '100vw',
'overflowY': 'scroll',
'display': 'flex',
'flexFlow': 'row wrap'
}let numBoxes = 10000;export class Style extends React.Component {
constructor(props) {
super(props);
} renderBoxes(boxStyle) {
let boxes = [];
for(var i = 0; i < numBoxes; i++) {
boxes.push(
<div style={boxStyle} key={i}>
</div>
)
} return boxes;
}render() {
let boxStyle = this.props.toggle ?
{...box, ...blue} :
{...box, ...red}
return (
<div style={container}>
{this.renderBoxes(boxStyle)}
</div>
)
}
}
Capturing an approx. 10 second timeline on chrome gives the below results.
Notice that with inline styles, the browser spends more time both scripting and rendering. It spends more time in scripting because it has to map all the styles rules passed in to the component to actual css rules (remember, you have to camelCase all your css rules when using inline css in react). It ends up spending more time rendering because it has to calculate the styles for 10,000 divs each second.
Enter CSS Modules. CSS Modules allow us to import styles directly from a css file — giving us the advantage of colocating jsx and css files while avoiding global names and without any performance overhead. The globally unique naming is made possible by webpack’s css loader. Adding a css loader configured as below (config taken from https://github.com/css-modules/webpack-demo)
{
test: /\.css?$/,
loader: ExtractTextPlugin.extract(
"style-loader",
"css-loader?modules
&importLoaders=1
&localIdentName=[name]__[local]___[hash:base64:5]") }
will generate globally unique names. The react component ends up looking like this —
import React from 'react';
import styles from './Style.css';let numBoxes = 10000;export class StyleCssModule extends React.Component {
constructor(props) {
super(props);
} renderBoxes(boxStyle) {
let boxes = [];
for(var i = 0; i < numBoxes; i++) {
boxes.push(
<div className={boxStyle} key={i}>
</div>
)
} return boxes;
} render() {
let boxStyle = this.props.toggle ?
`box ${styles.blue}` :
`box ${styles.red}`
return (
<div className={styles.container}>
{this.renderBoxes(boxStyle)}
</div>
)
}
}
The generated DOM would be something like this —
And now a side by side comparison of the timelines of all three approaches —
Swarup.