 i-plug Advent Calendar 2019 の【19日目】の記事です
 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 をちゃんと読もうって思いました


 **
**


