i-plug Advent Calendar 2019 の【19日目】の記事です
はじめまして、i-0701 です
この度 React を触ることになりまして、まずはボタンのコンポーネントを作成しよう!と思ったので、その備忘録を残します。
私が css まわりから作成していくタイプのため、今回は style 表示切り替え特化 です。(イベント処理に関しては今回書いておりません)
ちなみに使うものは
- CSS Module
- classnames
CSS Module ?
css で名前空間設定できるようなやつです。スコープしぼって使えるやつです。
1 個の css 修正してあそこもここも影響でた!!がなくて私は好きです。
共通なデザインの調整 css いっぱいやと、複数箇所修正する懸念がないこともないですが、コンポーネントなどはそれ特化の css するので問題ないはず。(最終、ここの margin は共通!って場合、sass で変数持ったらいいかもしれない)
あと、class名を考える時間が削減するので好きなのもあります。
create-react-app
node 動く状態で(私の環境は v10.13.0
)、create-react-app します。
今回は使いませんが、typescript 好きなので入れてます。
$ npx create-react-app ugoke --typescript
# npx create-react-app my-app --template typescript のが今正しかった
create-react-app した直後だと、webpack の設定だとかが見れないので、npm run eject 実行。
$ cd ugoke
$ npm run eject
コンポーネントと style.module.scss つくる
src 以下に Button コンポーネントを作成。
scss 動かしたいので、node-sass いれます。
$ npm install node-sass
あとは .module.scss
で作成すると勝手に create-react-app さんがええ感じにしてくれます。(CSS modules とかのモジュール入れなくても動く)
src
├── App.css
├── App.test.tsx
├── App.tsx
└── components
└── Button
├── Button.tsx
└── style.module.scss ← .module.scss にすること!
import React from 'react';
import styles from './style.module.scss';
// ちょっとの typescript 要素
interface Button {
text: string,
}
function Button(props: Button) {
return (
<button className={styles.button} onClick={props.event}>
{props.text}
</button>
);
}
export default Button;
.button {
display: inline-flex;
align-items: center;
justify-content: center; // color とか変数として持つほうがいいけど今回はしないです。
font-size: 14px;
background: #F1F1F1;
color: #333;
border-radius: 4px;
border: 1px solid #BFBFBF;
padding: 6px 12px;
cursor: pointer;
}
import React from 'react';
import './App.css';
import Button from './components/Button/Button';
const App: React.FC = () => {
return (
<div className="App">
<Button text="ボタン" />
</div>
);
}
export default App;
ちなみに
あとは
.module.scss
で作成すると勝手に create-react-app さんがええ感じにしてくれます。(CSS modules とかのモジュール入れなくても動く)
npm run eject
してでてきた config/webpack.config.js
を見ると、サポートしてるよって書いてくれてます。
今回だとの 457~490 行目あたりです。create-react-appさまさま
// Opt-in support for SASS (using .scss or .sass extensions).
// By default we support SASS Modules with the
// extensions .module.scss or .module.sass
{
test: sassRegex,
exclude: sassModuleRegex,
use: getStyleLoaders(
{
props によって style を変更する
今回は props によって見た目を disabled できるようにしてみます。
まずは複数の class 扱うのに便利な classnames を入れます。
$ npm install classnames --save
# 「型がない」って怒られるので入れます
$ npm install @types/classnames
CSS Module を使ってるのでこちら参照してコンポーネントを修正
import classNames from 'classnames/bind';
interface Button {
text: string,
disabled?: boolean,
}
let cx = classNames.bind(styles);
function Button(props: Button) {
let buttonClass = cx({
button: true, // ベースの class
disabled: props.disabled,
});
return (
<button className={buttonClass}>
{props.text}
</button>
);
}
disabled 用の class を書きます。
.button {
// 略
padding: 6px 12px;
cursor: pointer;
&.disabled {
cursor: default;
opacity: .65;
}
}
App で呼びます。
const App: React.FC = () => {
return (
<div className="App">
<Button text="ボタン" />
<Button text="ボタン" disabled={true} />
</div>
);
}
表示されました
左が通常ボタン、右が disabled なボタンです。
おまけ 失敗コードと感想
最初 CSS Module で以下みたいな書き方が分からず、
var btnClass = classNames({
btn: true,
'btn-pressed': this.state.isPressed,
'btn-over': !this.state.isPressed && this.state.isHovered
});
// これだと動かない
var btnClass = classNames({
'styles.button': true,
'styles.disabled': props.disabled,
});
こんな↓書き方してしまったんですが……公式を読むとちゃんと書いてました
const classNameForButton = () => {
if (props.disabled) {
return ClassNames(styles.button, styles.disabled);
}
return ClassNames(styles.button);
};
**公式 Docs をちゃんと読もうって思いました**