Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
14
Help us understand the problem. What is going on with this article?
@xiao

Material-UI使ってみた@VirtualBox(React+Redux+Express+Material-UI)

More than 3 years have passed since last update.

Material-UI使ってみた作業ログです。
目標は表題の組み合わせでエラー発生させずにMaterial-UIのコンポーネントを設置することです。

こんな感じになりました。
スクリーンショット 2016-05-05 12.02.45.png

環境作成

最近、環境は全部VirtualBox上に作っています。
ホストに作ってしまうと、しばらく使わない言語とか何入れてたっけ?となったり依存関係壊れてたりいろいろ面倒なのですが、VM上だと壊し放題なのが嬉しい。

参考サイト:
(というかほとんどそのままいただいたので、解説も読みたい場合はリンク先をおすすめ)
Vagrant+node.js+express4+MongoDBで簡単なWebアプリを構築

※以下VirtualBoxとVagrantのインストール済の前提。

OSインストール

環境を作成するディレクトリに移動したら

\$ vagrant init

でVagrantfileを作り、以下設定。

Vagrantfile
# -*- mode: ruby -*-
# vi: set ft=ruby :

# All Vagrant configuration is done below. The "2" in Vagrant.configure
# configures the configuration version (we support older styles for
# backwards compatibility). Please don't change it unless you know what
# you're doing.
Vagrant.configure(2) do |config|
  config.vm.box = "puphpet/centos65-x64"
  config.vm.hostname = "node.local"
  config.vm.network "private_network", ip: "192.168.33.10"
  config.vm.synced_folder "localのworkspace", "/var/www/html"
end

仮想環境を立ち上げる。
(プラグインでhostsの書き換えを自動化するとかなり便利)

\$ vagrant plugin install vagrant-hostsupdater
\$ vagrant up

各種インストール

nodeの設定

\$ vagrant ssh
\$ curl -L git.io/nodebrew | perl - setup
\$ echo 'export PATH=\$HOME/.nodebrew/current/bin:\$PATH' >> ~/.bashrc
\$ source ~/.bashrc
\$ nodebrew install-binary v5.10.1
\$ nodebrew use v5.10.1

node -vと打って、v5.10.1が表示されたら完了。

nginxを設定

\$ sudo yum install -y nginx
\$ sudo service nginx start
\$ sudo chkconfig nginx on
\$ sudo vi /etc/nginx/conf.d/virtual.conf

virtual.confは以下のように設定。

virtual.conf
server {
  listen 80;
  server_name node.local;
  location / {
    proxy_pass http://127.0.0.1:3000;
  }
}

ここまででとりあえずの設定は終了なので、(ついでにmongoDBとかも入れた上で)Box化しておくと便利。

Material-UIを使ってみる

React+Redux+Expressな環境を作る

参考サイト:
1. Material UIを使ってカッコいいUIのReactアプリケーションを作ってみた
2. React + Expressでのサーバーサイドレンダリング方法のまとめ

サイト2のgithubのからソースをそのまま頂戴しました。
めちゃくちゃ助かりました。。

\$ cd /var/www/html

で作業ディレクトリに移動してreact-router-reduxブランチのソースを落とします。
そのままnpm installすると落ちるので以下の作業を実施。

\$ npm install -g rimraf
\$ npm install isomorphic-fetch

Vagrantfileに設定したlocalのworkspaceに移動して、app/routes.jsxを以下のように修正。

routes.jsx
// import Route from 'react-router';
import { Route } from 'react-router';

※以下のエラーに悩まされたときの解決策として、こちらで発見しました。
Warning: React.createElement: type sh
ould not be null, undefined, boolean, or number. It should be a string (for DOM elements) or a ReactClass (for composite components).

Material-UIを追加

node_module追加

package.jsonに以下を追加します。

package.json
  "dependencies": {
    "material-ui": "^0.14.4",
    "react-tap-event-plugin": "^0.2.0",
    "inline-style-prefixer": "^1.0.3",

※最初material-uiのバージョン0.13.4を入れてDatePickerを使うと以下のエラーが出たので検索したところ、バージョン固有の問題っぽかったので最新バージョンに上げた。
 Invalid prop onDismiss of type boolean supplied to Dialog, expected function. Check the render method of DatePickerDialog

作業完了したら、

\$ npm install

でnode_moduleを追加・build

\$ npm start

http://node.local/
にアクセス。無事表示されたら環境設定は完了。

Material-UIを使う

ReduxとかReactについては追々ちゃんと勉強することにして、とりあえずMaterial-UIを動かす。
ディレクトリ構造をちょっと変更してimportのパスも変えておく。

/app
├── components
  ├── MainSection.jsx・・追加
  └── Header.jsx ・・追加
├── containers
  ├── App.jsx・・移動
  ├── Items.jsx・・移動
  ├── Users.jsx・・移動
  └── Material.jsx ・・追加
└── reducer

以下、追加変更内容。

routes.jsx
import React from 'react';
import { Route } from 'react-router';

import App from './containers/App';
import Items from './containers/Items';
import Users from './containers/Users';
import Material from './containers/Material';

export default (
  <Route path="/" component={App}>
    <Route path="items" component={Items} />
    <Route path="users" component={Users} />
    <Route path="material" component={Material} />
  </Route>
);
containers/Material.jsx
import React, { Component, PropTypes } from 'react';
import { connect } from 'react-redux';
import Header from '../components/Header';
import MainSection from '../components/MainSection';

class Material extends Component {

  static propTypes = {
    onDismiss: React.PropTypes.func,
  };

  render() {
    return (
      <div>
        <Header />
        <MainSection />
      </div>
    );
  }
}

export default Material;
components/Header.jsx
import React, { PropTypes, Component } from 'react';

import mui, {AppBar} from 'material-ui';
import themeDecorator from 'material-ui/lib/styles/theme-decorator';
import getMuiTheme from 'material-ui/lib/styles/getMuiTheme';

class Header extends Component {

  render() {
    return (
      <header className="header">
        <h1>AppBar Component</h1>
        <AppBar title="React + Redux + Material UI Boilerplate" />
      </header>
    );
  }
}

export default themeDecorator(getMuiTheme(null, { userAgent: 'all' }))(Header);
components/MainSection.jsx
import React, { Component, PropTypes } from 'react';

import mui, {CircularProgress,
             Tabs,
             Tab,
             DatePicker
            } from 'material-ui';
import themeDecorator from 'material-ui/lib/styles/theme-decorator';
import getMuiTheme from 'material-ui/lib/styles/getMuiTheme';

class MainSection extends Component {
  render() {
    return (
      <div>
        <h1>Progress Component</h1>
        <CircularProgress mode="indeterminate" size={1.5} />
        <CircularProgress mode="indeterminate" color={"red"} size={2} />
        <br/>

        <h1>Tab Component</h1>
        <Tabs>
          <Tab label="Tab One" value="0" />
          <Tab label="Tab Two" value="1" />
          <Tab label="Tab Three" value="2" />
        </Tabs>
        <br/>

        <h1>DatePicker Component</h1>
        <DatePicker hintText="Portrait Dialog" />
        <br/>
      </div>
    );
  }
}

export default themeDecorator(getMuiTheme(null, { userAgent: 'all' }))(MainSection);
client.jsx
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { Router, browserHistory } from 'react-router'
import configureStore from './configureStore';
import routes from './routes'
import injectTapEventPlugin from "react-tap-event-plugin";

const store = configureStore(window.APP_STATE);

//Needed for React Developer Tools
window.React = React;

//Needed for onTouchTap
//Can go away when react 1.0 release
//Check this repo:
//https://github.com/zilverline/react-tap-event-plugin
injectTapEventPlugin();

ReactDOM.render(
  <Provider store={store}>
    <Router history={browserHistory}>
      {routes}
    </Router>
  </Provider>,
document.getElementById('app'))

以下のエラーがなかなか消えなくて苦労したのですが、{ userAgent: 'all' }を入れることでとりあえず解消されました。

warning.js:45 Warning: React attempted to reuse markup in a container but the checksum was invalid. This generally means that you are using server rendering and the markup generated on the server was not what the client was expecting. React injected new markup to compensate which works but you have lost many of the benefits of server rendering. Instead, figure out why the markup being generated is different on the client or server:
(client) th:100%;display:flex;min-height:64px;pad
(server) th:100%;display:flex,-webkit-flex,-ms-fl

おわりに

まだ何にも分かっていないけどスタートラインにはぎりぎり立てたので、いろいろ作りながら探っていきたいと思います。
とりあえずで以下は勉強しなきゃ。。

追記

React+Redux+Material-UI、その後勉強しました。
この記事描いたころ何も理解していなかったなあと反省しきりです。。
罪滅ぼしに検索画面を作る入門記事とか書いたので、よかったら以下どうぞです。

React + Redux入門④ - 検索画面を作成2:外観と動作をつくる

14
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
xiao

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
14
Help us understand the problem. What is going on with this article?