Meteorのあんちょこ꒰｡･ω･`;꒱ ReactJS

# 概要

- [React - Meteor](https://www.meteor.com/tutorials/react/creating-an-app)（Tutorial）...simple-todosを作成

- **Virtual DOM**で高速にDOMを操作したい
 - **DOM**（Documment Object Model）...タグをオブジェクトとみなし、各オブジェクトに様々な命令を実行できるようにJavaScriptがHTML/XMLを認識しなおした構造体。
 - **VirtualDOM**...DOMをJSONに書出したもの。
 - DOMに操作する場合は、仮想DOMを操作した結果をDOMに反映する。
 - DOMを直接操作しなくなるため、最小限のDOM操作だけで済ませることが可能。
 - [VirtualDOMとは@のんびりコード]
- コンポーネント指向
- リアクティブプログラミング
- 関数型言語（プログラミング）

# サンプル（DB未接続）

- simple-todos

1.プロジェクト作成

- [Creating your first app @ Meteor Tutorial](https://www.meteor.com/tutorials/react/creating-an-app)

```bash:console
$ meteor cretate simple-todos
$ cd simple-todos/
```

2. npmインストール

```bash:console
$ meteor npm install
```

3.起動確認

```bash:console
$ meteor
```

4.react追加

- [Defining views with React components @ Meteor Tutorial](https://www.meteor.com/tutorials/react/components)

```bash:console
$ meteor npm install --save react react-dom
```

5.React View Component 定義


```html:client/main.html
<head>
  <title>Todo List</title>
</head>

<body>
  <div id="render-target"></div><!-- App Component を展開-->
</body>
```

```js:client/main.js
import React from 'react';
import { Meteor } from 'meteor/meteor';
import { render } from 'react-dom';

import App from '../imports/ui/App.jsx';

Meteor.startup(() => {
  // 'render-target'にApp Componentを展開する。
  render(<App />, document.getElementById('render-target'));
});

```

```jsx:imports/ui/App.jsx
import React, { Component } from 'react';

import Task from './Task.jsx';

// App component - represents the whole app
export default class App extends Component {
  getTasks() {
    // JSONとして返却する。
    return [
      { _id: 1, text: 'This is task 1' },
      { _id: 2, text: 'This is task 2' },
      { _id: 3, text: 'This is task 3' },
    ];
  }

  // Taskを取得し、map関数でTaskを表示する。
  renderTasks() {
    return this.getTasks().map((task) => (<Task key={task._id} task={task} />));
  }

  // App render <App/>
  render() {
    return (
      <div className="container">
        <header>
          <h1>Todo List</h1>
        </header>

        <ul>
          {this.renderTasks()} 
        </ul>
      </div>
    );
  }
}
```

```jsx:imports/ui/Task.jsx
import React, { Component, PropTypes } from 'react';

// Task component - represents a single todo item
export default class Task extends Component {
  render() {
    return (
      <li>{this.props.task.text}</li>
      //<li>{this.props.task.text}(id={this.props.task._id})</li>
    );
  }
}

Task.propTypes = {
  // This component gets the task to display through a React prop.
  // We can use propTypes to indicate it is required
  task: PropTypes.object.isRequired,
};
```

```css:client/main.css
/* CSS declarations go here */
body {
  font-family: sans-serif;
  background-color: #315481;
  background-image: linear-gradient(to bottom, #315481, #918e82 100%);
  background-attachment: fixed;

  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  right: 0;

  padding: 0;
  margin: 0;

  font-size: 14px;
}

.container {
  max-width: 600px;
  margin: 0 auto;
  min-height: 100%;
  background: white;
}

header {
  background: #d2edf4;
  background-image: linear-gradient(to bottom, #d0edf5, #e1e5f0 100%);
  padding: 20px 15px 15px 15px;
  position: relative;
}

#login-buttons {
  display: block;
}

h1 {
  font-size: 1.5em;
  margin: 0;
  margin-bottom: 10px;
  display: inline-block;
  margin-right: 1em;
}

form {
  margin-top: 10px;
  margin-bottom: -10px;
  position: relative;
}

.new-task input {
  box-sizing: border-box;
  padding: 10px 0;
  background: transparent;
  border: none;
  width: 100%;
  padding-right: 80px;
  font-size: 1em;
}

.new-task input:focus{
  outline: 0;
}

ul {
  margin: 0;
  padding: 0;
  background: white;
}

.delete {
  float: right;
  font-weight: bold;
  background: none;
  font-size: 1em;
  border: none;
  position: relative;
}

li {
  position: relative;
  list-style: none;
  padding: 15px;
  border-bottom: #eee solid 1px;
}

li .text {
  margin-left: 10px;
}

li.checked {
  color: #888;
}

li.checked .text {
  text-decoration: line-through;
}

li.private {
  background: #eee;
  border-color: #ddd;
}

header .hide-completed {
  float: right;
}

.toggle-private {
  margin-left: 5px;
}

@media (max-width: 600px) {
  li {
    padding: 12px 15px;
  }

  .search {
    width: 150px;
    clear: both;
  }

  .new-task input {
    padding-bottom: 5px;
  }
}
```

6.動作確認

```bash:console
$ meteor
```

# DB接続

- [Storing tasks in a collection @ Meteor Tutorial](https://www.meteor.com/tutorials/react/collections)

- MongoDBのtasksコレクションとTaskを関連付ける。 

```jsx:imports/api/tasks.js
  :
import { Mongo } from 'meteor/mongo';
export const Tasks = new Mongo.Collection('tasks');
  :
```

```js:server/main.js
  :
import '../imports/api/tasks.js';
  :
```

----

# React Meteor 関連付け

- React Componentに含まれるコレクションのデータを使用するためには、Atmosphere パッケージ **react-meteor-data**を使用する
- react-meteor-dataでは、MeteorのリアクティブデータをReactのコンポーネント階層に受け渡すデータコンテナを生成できる。


```bash:console
$ meteor npm install --save react-addons-pure-render-mixin
$ meteor add react-meteor-data
```

```jsx:App.jsx
import React, { Component, PropTypes } from 'react';
import { createContainer } from 'meteor/react-meteor-data';

import { Tasks } from '../api/tasks.js';

import Task from './Task.jsx';

// アプリケーション全体に提示されるApp Component
// App component - represents the whole app
class App extends Component {
// export default class App extends Component {

  // getTasks() {
  //   // JSONとして返却する。
  //   return [
  //     { _id: 1, text: 'This is task 1' },
  //     { _id: 2, text: 'This is task 2' },
  //     { _id: 3, text: 'This is task 3' },
  //   ];
  // }

  // Taskを取得し、map関数でTaskを表示する。
  renderTasks() {
    // (3)App(this).propsに対して、Task Componentを表示する。
    return this.props.tasks.map((task) => (
    // return this.getTasks().map((task) => (
      <Task key={task._id} task={task} />
    ));
  }

  render() {
    return (
      <div className="container">
        <header>
          <h1>Todo List</h1>
        </header>

        <ul>
          {this.renderTasks()}
        </ul>
      </div>
    );
  }
}

App.propTypes = {
  // (2) App(this).props.tasks
  tasks: PropTypes.array.isRequired,
};

export default createContainer(() => {
    return {
      // (1)tasksにDBのTasks(tasks)の全データを取得し、フェッチする
      tasks: Tasks.find({}).fetch(),
    }
  };
}, App);
```

- 動作確認 
- DBにダミーデーターを登録し、DBからデータが取得できることを確認する。

```bash:console
$ meteor mongo
> db.tasks.insert({ text: "Hello world!", createdAt: new Date() });
> exit
$ meteor
```

----

# データ追加


- [Adding tasks with a form @ Meteor Tutorial](https://www.meteor.com/tutorials/react/forms-and-events)