LoginSignup
5
0

More than 3 years have passed since last update.

React 状態によってデザインの変わるボタンコンポーネント作成(CSS Module, classnames)

Posted at

:calendar_spiral: i-plug Advent Calendar 2019 の【19日目】の記事です:santa::tada:

はじめまして、i-0701 です:boy::boy_tone4::boy_tone1::boy_tone2::boy_tone3:

この度 React を触ることになりまして、まずはボタンのコンポーネントを作成しよう!と思ったので、その備忘録を残します。
私が css まわりから作成していくタイプのため、今回は style 表示切り替え特化 です。(イベント処理に関しては今回書いておりません:cry:

ちなみに使うものは
- 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 にすること!
Button.tsx
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;
style.module.scss
.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;
}
App.tsx
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;

表示されました:blush:
スクリーンショット 2019-12-13 16.24.44.png

ちなみに

あとは .module.scss で作成すると勝手に create-react-app さんがええ感じにしてくれます。(CSS modules とかのモジュール入れなくても動く)

npm run eject してでてきた config/webpack.config.js を見ると、サポートしてるよって書いてくれてます。
今回だとの 457~490 行目あたりです。create-react-appさまさま:pray:

config/webpack.config.js
            // 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 を使ってるのでこちら参照してコンポーネントを修正

Button.tsx
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 を書きます。

style.module.scss
.button {

  // 略

  padding: 6px 12px;
  cursor: pointer;

  &.disabled {
    cursor: default;
    opacity: .65;
  }
}

App で呼びます。

App.tsx
const App: React.FC = () => {
  return (
    <div className="App">
      <Button text="ボタン" />
      <Button text="ボタン" disabled={true} />
    </div>
  );
}

表示されました:blush:
左が通常ボタン、右が disabled なボタンです。
スクリーンショット 2019-12-18 18.43.24.png

おまけ :yum: 失敗コードと感想

最初 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,
  });

こんな↓書き方してしまったんですが……公式を読むとちゃんと書いてました:bow_tone2:

  const classNameForButton = () => {
    if (props.disabled) {
      return ClassNames(styles.button, styles.disabled);
    }
    return ClassNames(styles.button);
  };



公式 Docs をちゃんと読もうって思いました:bangbang::bangbang::bangbang:

5
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
0