ざっくり要約
- Reactのスタイリングの種類は
style属性
,CSS Modules
,CSS-in-JS
などがある CSS Modules
は標準のCSSの記法で書けるため導入しやすいが、JestのSnapshotテストで使用することができないstyle属性
はReact公式で非推奨なので、上記を考えるとCSS-in-JS
を採用するのがいいと判断した
目次
Reactのスタイリングのいろいろ
CSS ModulesはJestのSnapshotテストと相性が悪い
CSS-in-JS(styled-components)でスナップショットテスト
まとめ
Reactのスタイリングのいろいろ
Reactのスタイリングには様々な手法があります。
例えば
style属性にCSSPropertiesオブジェクトを渡すパターン
importReact,{CSSProperties,FC}from"react";exportconstButton:FC=()=>{return(<spanstyle={style}><span>ボタン</span></span>);};conststyle:CSSProperties={alignItems:"center",backgroundColor:"orange",cursor:"pointer",display:"inline-flex",fontSize:"14px",fontWeight:"bold",};
CSS Modulesを使用するパターン
importstylesfrom"./button.module.css";exportconstButton:FC=()=>{return(<spanclassName={styles.button}><span>ボタン</span></span>);};
.button{align-items:center;background-color:orange;cursor:pointer;display:inline-flex;font-size:14px;font-weight:bold;}
CSS-in-JSを使用するパターン
※CSS in JSには様々なツールがありますが、今回はstyled-componentsを使用した例を紹介します。
importReact,{FC}from"react";importstyledfrom"styled-components";exportconstTextButton:FC=()=>{return(<Body><span>ボタン</span></Body>);};constBody=styled.span`
align-items: center;
background-color: orange;
cursor: pointer;
display: inline-flex;
font-size: 14px;
font-weight: bold;
`;
このようにReactでは、スタイリングだけで様々な手法があるので、サービス開発をする上でどのスタイリング手法を選択するべきか開発者の頭を悩ませます。
CSS ModulesはJestのSnapshotテストと相性が悪い
数多あるスタイリング手法の中で、自分は元々CSS Modulesを採用していました。
- 通常のCSSの記法で書けるため、学習コストが低い
- スコープをコンポーネント内部に閉じ込めることができる
ことが主な理由でした。
ですが、各コンポーネントごとでJestのスナップショットテストを実施しようとすると下記のようなエラーになります。
importReactfrom"react";importrendererfrom"react-test-renderer";import{Button}from"../Button";test("Button",()=>{constcomponent=renderer.create(<Button/>);consttree=component.toJSON();expect(tree).toMatchSnapshot();});
jestだとCSS Modulesを読み込むことができないため起きるエラーです。jest-css-modules
というライブラリを使用してjest.config.js内に下記のような設定をするとエラーの回避はできるようになります。
module.exports={...moduleNameMapper:{"\\.(css|less|scss|sss|styl)$":"<rootDir>/node_modules/jest-css-modules",},...};
ですが、このライブラリはjest内でバンドルする際にCSS Modulesを読み込んでいるわけではなく、単に上記エラーを回避しているだけなので、CSS Modulesのスタイルを変更しても、テストを通過してしまいます。
.button{align-items:center;/* orangeをredに変更 */background-color:red;cursor:pointer;display:inline-flex;font-size:14px;font-weight:bold;}
スナップショットテストでスタイリングが反映されていないのはほとんど意味がないと思い、スタイリングの方式を切り替えることにしました。
CSS-in-JS(styled-components)でスナップショットテスト
他の選択肢としてはstyle属性
を使ったスタイリングもありえますが、公式で非推奨とされています。
Some examples in the documentation use style for convenience, but using the style attribute as the primary means of styling elements is generally not recommended.
便宜上style属性をドキュメント内で使用していますが、要素のスタイリングとしてスタイル属性を使うことは一般的に推奨されていません。
そのため、CSS-in-JS(styled-components)を採用したいと思いますが、その前に、Snapshotテストでスタイリングの変更が検知できるか確認をします。
importReact,{FC}from"react";importstyledfrom"styled-components";exportconstTextButton:FC=()=>{return(<Body><span>ボタン</span></Body>);};constBody=styled.span`
align-items: center;
background-color: orange;
cursor: pointer;
display: inline-flex;
font-size: 14px;
font-weight: bold;
`;
スタイルを少し変更します。
importReact,{FC}from"react";importstyledfrom"styled-components";exportconstTextButton:FC=()=>{return(<Body><span>ボタン</span></Body>);};constBody=styled.span`
align-items: center;
/* orangeをredに変更 */
background-color: red;
cursor: pointer;
display: inline-flex;
font-size: 14px;
font-weight: bold;
`;
ただ、この差分の内容だと、styled-componentsが自動生成したclassNameが変わっていることは確認できますが、具体的なスタイルの変更内容までは分かりません。
それでも、自分が行ったスタイルの修正がどのコンポーネントに影響を及ぼしているのか分かると、スナップショットテストの有用性は高まると考えています。
まとめ
Reactのスタイリング手法は、CSS-in-JS
だけでも今回紹介したstyled-components
以外にstyled-jsx
などがあったり、本当に様々な選択肢があります。
今回はスナップショットテストとの相性という観点でのスタイリング手法の選択の意思決定をまとめてみました。
またpros,cons比較すると違う選択もありえるかもしれないので、その際にはまたアップデートして記事として紹介したいと思います。