React でも Bootstrap のコンポーネントを使う

React で SPA を実装する場合も、 デザインは Bootstrap のお世話になりたい。 クラスを指定するだけで使えるコンポーネントは普通に使えそうだけど、 Tooltip や Dropdown や Modal のような、 jQuery に依存したコンポーネントは React でそのまま使えないのが残念。

そこで Bootstrap のコンポーネントを React コンポーネントとして実装した、 React-Bootstrap を試してみた。

github.com

JavaScript の部分を jQuery から React に実装し直したシロモノなので、 別途 Bootstrap の CSS は必要。

Bootstrap を使って自分がよくやるレイアウトを React-Bootstrap で再現してみた。

var React = require("react");
var ReactDOM = require("react-dom");

// React-Bootstrap のコンポーネントを読み込む
var Navbar = require("react-bootstrap").Navbar;
var Nav = require("react-bootstrap").Nav;
var NavItem = require("react-bootstrap").NavItem;
var NavDropdown = require("react-bootstrap").NavDropdown;
var MenuItem = require("react-bootstrap").MenuItem;
var Grid = require("react-bootstrap").Grid;
var Row = require("react-bootstrap").Row;
var Col = require("react-bootstrap").Col;
var Table = require("react-bootstrap").Table;
var Tabs = require("react-bootstrap").Tabs;
var Tab = require("react-bootstrap").Tab;
var Button = require("react-bootstrap").Button;
var Modal = require("react-bootstrap").Modal;
var Input = require("react-bootstrap").Input;

// Navbar を使ってヘッダーを作成
var Header = React.createClass({
  render: function() {
    return (
      <Navbar>
        <Navbar.Header>
          <Navbar.Brand>
            <a href="#">React-Bootstrap Sample</a>
          </Navbar.Brand>
        </Navbar.Header>

        <Nav pullRight>
          <NavDropdown eventKey={1} title="Settings" >
            <MenuItem eventKey={1.1}>Profile</MenuItem>
            <MenuItem divider />
            <MenuItem eventKey={1.2}>Sign out</MenuItem>
          </NavDropdown>
        </Nav>
      </Navbar>
    );
  }
});

// Nav を使ってメニューを作成
var SideNav = React.createClass({
  render: function() {
    return (
      <Nav bsStyle="pills" activeKey={1} stacked>
        <NavItem eventKey={1} href="#">Home</NavItem>
        <NavItem eventKey={2} href="#">About</NavItem>
        <NavItem eventKey={3} href="#">Contact</NavItem>
      </Nav>
    );
  }
});

// 登録フォームを作成
var MemberForm = React.createClass({
  render: function() {
    return (
      <form>
        <Input type="text" label="Number" />
        <Input type="text" label="Name" placeholder="Name text" />
        <Input type="select" label="Position">
          <option value="FW">FW</option>
          <option value="MF">MF</option>
          <option value="DF">DF</option>
          <option value="GK">GK</option>
        </Input>
      </form>
    );
  }
});

// モーダルを表示するボタンを作成
var AddMember = React.createClass({
  getInitialState: function() {
    return {
      showModal: false
    }
  },
  
  close: function() {
    this.setState({ showModal: false });
  },

  open: function() {
    this.setState({ showModal: true });
  },

  render: function() {
    return (
      <div>
        <Button onClick={this.open}>Add</Button>

        <Modal show={this.state.showModal} onHide={this.close}>
          <Modal.Header closeButton>
            <Modal.Title>Add Member</Modal.Title>
          </Modal.Header>
          <Modal.Body>
            <MemberForm />
          </Modal.Body>
          <Modal.Footer>
            <Button bsStyle="primary" onClick={this.close}>Save</Button>
            <Button onClick={this.close}>Cancel</Button>
          </Modal.Footer>
        </Modal>
      </div>
    );
  }
});

// Table を使ってメンバー一覧を作成
var Members = React.createClass({
  render: function() {
    return (
      <Table striped>
        <thead>
          <tr>
            <th>Number</th>
            <th>Name</th>
            <th>Position</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td>10</td>
            <td>Kagawa</td>
            <td>MF</td>
          </tr>
          <tr>
            <td>4</td>
            <td>Honda</td>
            <td>MF</td>
          </tr>
          <tr>
            <td>5</td>
            <td>Nagatomo</td>
            <td>DF</td>
          </tr>
          <tr>
            <td>9</td>
            <td>Okazaki</td>
            <td>FW</td>
          </tr>
        </tbody>
      </Table>
    );
  }
});

// Grid と Row と Col を使ってグリッドレイアウト
var MyApp = React.createClass({
  render: function() {
    return (
      <div class="wrap">
        <Header />

        <Grid>
          <Row>
            <Col md={3}>
              <SideNav />
            </Col>
            <Col md={9}>
              <AddMember />

              <Tabs defaultActiveKey={1}>
                <Tab eventKey={1} title="Start">
                  <Members />
                </Tab>
                <Tab eventKey={2} title="Sub"></Tab>
                <Tab eventKey={3} title="Other"></Tab>
              </Tabs>
            </Col>
          </Row>
        </Grid>
      </div>
    );
  }
});

ReactDOM.render(
  <MyApp />,
  document.getElementById("content")
);

Navbar が内部で container を持っているから、ヘッダーやフッター以外では使えないな。 Navbar は自分でコンポーネントを書くことにしよう。 Dropdown や Modal はそのまま使えそうだ。 React-Bootstrap 結構使えるかもしれないな。