Umi Uyuraのブログ

プログラミング関連の作業ログ

Material UIをLESSからInline Style方式にアップデートした

ReactとNW.jsでツールなど作っていたときに、デザインフレームワークとして Material UI を使ってみました。

umi-uyura.hatenablog.com

そのときのバージョンは0.7.5だったのですが、その後バージョンアップした0.8.0のタイミングでBreaking Changeが入ってしまい、それまでと実装方法が大きく変わってしまったようなので、新しいもので動くように修正してみました。

なお、0.8.0が出たタイミングで一度トライしたのですが、後述するエラーが出てしまってすんなりかなかったので、保留にしていたのですが、その後、1ヶ月経たないうちに0.9.2になっていたので、今回はそのバージョンで試しています。

大きな変更点

Reactベースのコンポーネントが提供されているという点は変わっていないのですが、0.7.xまではLESSで書かれていたCSSが、0.8.0でInline Style方式の実装に変更になりました。

Inline Style方式については、@koba04さんの 一人React.js Advent Calendar 2014 - Qiita でも紹介されている( reactjs - React.js + CSS - Qiita ) の資料が参考になるようです。

特定のCSSフレームワークに依存していたのは、私のようにLESSに馴染みがない人間としては取っ付きにくくなってしまうため、選択肢を増やす意味でも、この変更点は良いものだと思います。

また、合わせてテーマという機能が導入されていることもあり、0.7系ベースのコードのままでは動かないようです。

修正した箇所

先日、0.7.5ベースで作っていたReactとNW.jsとMaterial UIのサンプルをアップデートしました。

umi-uyura/react-nwjs-materialui-sample

トランスパイラをBabelifyへ変更

本題ではないですが、先日の発表を受けて、Reactify(react-tools)からBabelifyへ乗り換えることにしたので、同様にこのサンプルもBabelifyを使うようにしています。

umi-uyura.hatenablog.com

LESSからInline StyleおよびCSSへ分離

LESSで書いていたものを、ノーマルなCSSにします。

と言っても、サンプルではあまりスタイルは当てておらず、Material UIで提供されていた.lessを @import していただけなので、大きな影響はなし。

ただ、背景色にMaterial UIで提供されていた変数を参照していたので、この部分はいったん削除。

body {
  background-color: @deep-purple-A100;
}

index.htmlで、LESSをコンパイルしたCSSを参照していたところを、ノーマルなCSSに変更しておきました。

<link rel="stylesheet" type="text/css" href="style/app.css" />

テーマ対応とルートコンポーネントを設置

CSSを置き換えれば動くかな、と思っていたのですが、その状態で動かしてみたところ、使っていたRaisedButtonで

TypeError: Cannot read property 'component' of undefined

というエラーが発生しました。

GitHubのissueにも似たようなケースがありました。

this.context.muiTheme is undefined · Issue #686 · callemall/material-ui

上記issueを見ていると、どうやらテーマ機能が導入されたためか、コンポーネントに以下のようなコードが必要なようでした。

var SomeAwesomeComponent = React.createClass({
  ...

  childContextTypes: {
    muiTheme: React.PropTypes.object
  },

  getChildContext: function() {
    return {
      muiTheme: ThemeManager.getCurrentTheme()
    };
  },

  ...
});

最初は問題が発生したRaisedButton派生コンポーネントに上記を追加していたのですが、

material-ui/main.jsx at master · callemall/material-ui

上記のexampleのコードを見ていたところ、アプリのルートとなるコンポーネントを用意して、そこに書いておけば、子コンポーネントが、それを参照してくれるようだと気付きました。

そこで、当初サンプルにはなかった、アプリのルートとなるコンポーネントを用意して、そこに上記のコードを仕込んで置いたところ、問題のエラーも発生せず、動作しました。

var App = React.createClass({
  childContextTypes: {
    muiTheme: React.PropTypes.object
  },
  getChildContext: function() {
    return {
      muiTheme: ThemeManager.getCurrentTheme()
    };
  },
  render: function() {
    var style = {
      width: '100%',
      height: '100%',
      backgroundColor: mui.Styles.Colors.deepPurpleA400
    };

    return (
      <div style={style}>
        <Hello name='Material' />
        <Hi />
      </div>
    );
  }
});

React.render(
  <App />,
  document.body
);

また、ルート要素を作ったことで、当初設定していた背景色も設定する場所ができました。

Inline Style方式でのカラーコードは mui.Styles.Colors.deepPurpleA400 のように参照できます( muirequire('material-ui') したもの)。

f:id:umi-uyura:20150622193517p:plain

感想

本格的に使うことがあれば、もう少しテーマの使い方を掘り下げておきたいところです。

参考