Murayama blog.

it works.

AIにおける知的財産の考え方について

「AI白書2017 3.2 知的財産」の自分用まとめです。AIの活用シーンにおける以下の3点についてまとめます。

  • AI生成物
  • 学習済みモデル
  • 学習用データ

f:id:yamasahi:20171110180510p:plain

注意:以下に示す内容は現在も議論されている段階です。

AI生成物の著作権保護

音楽や文学作品などのコンテンツを学習することで、新たな創作が可能になりつつあります。たとえばAIを活用して生成された音楽コンテンツには次のようなものがあります。

このようなAI生成物の著作権の取り扱いについて「次世代知財システム検討委員会報告書」には以下の記載があります。

AI生成物を生み出す過程において、学習済みモデルの利用者に創作意図があり、同時に、具体的な出力であるAI生成物を得るための創作的寄与があれば、利用者が思想感情を創作的に表現するための「道具」としてAIを使用して当該AI生成物を生み出したものと考えられることから、当該AI生成物には著作物性が認められその著作者は利用者となる

上記は著作権が認められるケースです。「創作意図」があるかどうかがポイントになるようです。

一方で、利用者の寄与が、創作的寄与が認められないような簡単な指示に留まる場合(AIのプログラムや学習済みモデルの作成者が著作者となる例外的な場合を除く)、当該AI生成物は、AIが自律的に生成した「AI創作物」であると整理され、現行の著作権法上は著作物と認められないこととなる

AIが自律的に生成した成果物は、著作物に該当せず著作権も発生しないと考えられます。

たとえば先のDaddy' Carは、作曲家(Benoit Carre氏)が「ビートルズ風」というスタイルと曲の長さを指定して生成し、作詞・編曲を行っているため、創作的寄与があると考えられます。つまり著作権が発生すると考えられます。

一方で、lamusによる楽曲はAIのみで自律的に制作されているそうです。そのため「AI創作物」として著作権は認められない、と考えられます。

学習済みモデルの保護

学習済みのモデルはプログラムとパラメータで構成されており、著作権法上の「プログラムの著作物」に該当するか議論されています。仮に該当しないとしても、特許法上では「プログラム等」に該当するならば、特許法の要件を満たすなら保護される可能性があります。

また上記に該当しない場合でも不正競争帽子北条の秘密管理性、有用性、非公知性といった要件を満たす場合は「営業秘密」として保護されるようです。

(正直、この辺は専門外なのでちょっと難しい。。)

蒸留モデル

学習済みモデルに対して、データの入出力を繰り返し、その結果を別の学習モデルに学習させることもできます。このように作られたものは「蒸留モデル」と呼ばれます。

蒸留モデルは、元のモデルからの依拠性を証明することが難しく、著作権による保護が困難になります。一方で、特許権による保護は、依拠性の立証がなくても認められるため、特許権の範囲での対応も議論されています。

また学習済みモデルの利用規約により、蒸留モデルを禁止する等の契約で保護することもできます。この場合契約当事者以外の第三者から守ることはできないものの、柔軟な対応が可能となります。

学習データについて

AI白書には以下の一文があります。

インターネット上のデータ等の著作物を元に学習用データを作成・解析することは営利目的の場合も含めて、著作権法47条の7に基づいて著作権侵害には当たらないとされており、機械学習活用の促進にとって我が国特有の有用な制度となっている。(AI白書より)

学習データについては著作権法47条の7がポイントのようです。以前、こちらの記事も話題になっていました。

www.itmedia.co.jp

日本はインターネット上のデータを機械学習に活用しやすい一方で、AIの研究開発推進に向けての国産の共有データセット(ImageNetのようなもの)の整備が遅れているとの指摘もあります。

それから著作権法47条の7の規定は、もともと機械学習の促進を想定したものではないため、解釈の仕方や議論の余地が残っています。

共有データセットについての問題

海外にはImageNetやMNIST、MS COCOといった共有データセットが存在します。また、これらのデータを活用して、事前に学習済みのモデルも公開されています。

これらの学習済みモデルは、欧米で作られた共有データセットで作られている点を理解しておく必要があります。そのため日本固有の「ラーメン」のような画像認識ができない、といった問題があります。

参考書籍

AI白書 2017

AI白書 2017

Jupyter Notebookで始めるPythonプログラミング

Python機械学習始めたい方向けのまとめです。

Python

PythonはWebアプリの開発からちょっとしたツールの開発まで、多目的に利用できるプログラミング言語です。また機械学習ライブラリが充実しているため近年注目を集めています。

www.python.org

次のAnacondaディストリビューションPythonをインストールすることもできます。

Anaconda

Python機械学習を始めるにはCONTINUUM社の配布しているはAnacondaディストリビューションを活用すると良いでしょう。以下のURLからダウンロートすることができます。

www.continuum.io

AnacondaにはPython本体だけでなく機械学習に必要なライブラリも梱包されているため、Anacondaをインストールすればすぐに機械学習プログラミングを始めることができます。

Jupyter Notebook

AnacondaにはJupyter Notebookというブラウザ上で動作するPython開発環境も付属しています。ターミナル(コマンドプロンプト)上で jupyter-notebook コマンドを実行するとローカルでサーバプログラムが起動し、ブラウザが起動します。

jupyter.org

Jupyter Notebookの起動方法について補足しておきます。Anacondaインストール後、Windowsでは画面左下のWindowsメニューから「jupyter-notebook」とタイプするとアプリが見つかります。Macでは、ターミナル上でjupyter-notebookコマンドをタイプします。Jupyter Notebookはデフォルトで8888番ポートを使って起動します。ブラウザで http://localhost:8888/ にアクセスすると開発画面が表示されるでしょう。

Jupyter Notebookでは、ノートブックという形式でファイルを作成できます。ノートブックにはPythonコードや実行結果だけでなく、Markdown形式で文章を挿入することもできるので、データ分析の評価レポートを作成しやすいようになっています。またノートブックファイルは拡張子.ipynbという形式保存されます。.ipynbファイルはGitHubやGistなどでも表示できます。

クラウド上でJupyter Notebookを起動する

Jupyter Notebookの実体はブラウザで利用するWebアプリケーションです。そのためサーバ上でJupyter Notebookを起動すれば、手元のパソコンのブラウザからサーバ上でPythonプログラムを実行することも可能です。

ここではあらかじめJupyter環境をインストール済みのDockerコンテナを起動する方法を紹介します。またDeepLearning開発を支援するPaaS型サービスであるFloydHubを紹介します。

DockerでJupyter環境を構築するには

ここではクラウド環境としてAWSのEC2インスタンスUbuntu / Small)があるものとします。

sshでEC2インスンタンスにログインします。まずUbuntuのパッケージ情報を更新しておきます。

sudo apt update

次にDockerをインストールします。

sudo apt install docker.io -y

Dockerコンテナ(murayama333/ai-prog)を起動します。

sudo docker run -p 8888:8888 --name ai-prog -it murayama333/ai-prog

Dockerの出力ログにURLが表示されます。URLはlocalhostとなっているので、EC2のグローバルIPに置き換えてアクセスすると完了です。

ここで利用したDockerイメージはこちらの記事を参考に作っています。勉強になりました。

dr-asa.hatenablog.com

FloydHubで開発する

Dockerを使えばあっという間に開発環境を構築できますが、FloydHubを使えばもっと手軽にJupyter環境を整えることもできます。

FloydHub - Deep Learning Platform - Cloud GPU

FloydHubを一言で説明するなら

FloydHub is Heroku for DL

FloydHubはDeepLearningのためのHerokuです。つまり、DeepLearningのためのPaaS(Platform as a Service)です。FloydHubの素晴らしいところは、クラウド上ですぐに開発&実行ができるだけでなく、GPUインスタンスを利用することができる点です。無料アカウントの場合、GPUインスタンスは 2時間 / 月 まで利用できます。

FloydHub - Deep Learning Platform - Cloud GPU

FloydHub上でアカウントを作成後、開発キット(floyd-cli)をインストールします。

pip install -U floyd-cli

pipはPythonライブラリの追加コマンドです。pipコマンドを利用するにはローカルにPythonがインストールされている必要があります。

floydコマンドが有効になるので、FloydHubにログインします。

$ floyd login

以下、オフィシャルのクイックスタートを参考に動かしてみましょう。

https://docs.floydhub.com/getstarted/quick_start/

GitHubからサンプルのリポジトリをダウンロードしておきます。

git clone https://github.com/floydhub/quick-start.git
cd quick-start

リポジトリの中のファイルの一覧を確認しましょう。

ls
eval.py  LICENSE  mnist_cnn.ipynb  README.md  train_and_eval.py  train.py

以降は、上記の train_and_eval.py プログラムをFloydHub上で実行してみます。

FloydHubプロジェクトを初期化します。

floyd init mnist-cnn

FloydHubでPythonプログラムを実行してみましょう。

floyd run --gpu --env tensorflow-1.3 "python train_and_eval.py"

ここでは --gpu オプションを指定してるので、GPUインスタンス上で実行されます。

FloydHubでJupyter Notebookを起動する

FloydHubのプロジェクトフォルダ上で(先のquick-startフォルダなど)、次のようにコマンドを実行します。

floyd run --mode jupyter

Creating project run. Total upload size: 198.0B
Syncing code ...
[================================] 946/946 - 00:00:00

JOB NAME
-----------------------------------
murayama333/projects/mnist-cnn/1

Setting up your instance and waiting for Jupyter notebook to become available .............

Path to jupyter notebook: https://floydlabs.com/notebooks/xxx

数秒(数十秒)でJupyterが起動します。

GPUインスタンスで起動する場合は、次のように指定します。

floyd run --gpu --mode jupyter

Jupyterを起動している間、GPUインスタンスの利用時間がカウントされるので、利用を終えたらインスタンスを停止しておきましょう。停止するときは JOB NAME(floyd run時のログを参照)を指定します。

floyd stop murayama333/projects/mnist-cnn/1

Reactだけ学ぶハンズオン

Reactだけ学ぶハンズオン

  1. Hello React・・・はじめてのReact
  2. Greeting・・・プロパティを学ぶ
  3. GreetingList・・・コレクションの考え方を学ぶ
  4. Echo・・・ステートを学ぶ
  5. Welcome・・・コンポジットなコンポーネントの作り方を学ぶ

昔の勉強会の資料です。内容古かったらすみません。

こっちのが見やすいかもです。

https://github.com/murayama333/react-handson

Reactだけ学ぶハンズオン 5/5

Part5 Welcome - ハンズオン

ここでは入力した内容を表示するReactアプリケーションを作成します。

20170915200531

開発は以下の手順で進めます。

  1. ライブラリの設定
  2. コンポーネント仕様を定義
  3. コンポーネントクラスをレンダリング

1. ライブラリの設定

titleタグ以外は前章と同じです。ファイル名は05_welcome.htmlという名前で保存しておきます。

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Hello React 05</title>
  <script src="https://unpkg.com/react@15.6.1/dist/react.js" charset="utf-8"></script>
  <script src="https://unpkg.com/react-dom@15.6.1/dist/react-dom.js" charset="utf-8"></script>
  <script src="https://unpkg.com/babel-standalone@6.15.0/babel.js"></script>
</head>
<body>
  <div id="example"></div>
  <script type="text/babel">
  </script>
</body>
</html>

2. コンポーネント仕様を定義

ここでは以下のコンポーネントを作成します。

  • Welcome
    • GreetingList
      • GreetingItem(*)
    • Echo

コンポーネント仕様は次のようになります。

class GreetingItem extends React.Component {
  render() {
  }
}

class GreetingList extends React.Component {
  render() {
  }
}

class Echo extends React.Component {
  constructor(props) {
  }

  echo(e){
  }

  isEnterKey(e){
  }

  render() {
  }
}

class Welcome extends React.Component {
  constructor(props) {
  }

  save(completeName){
  }

  echo(incompleteName){
  }

  render(){
  }
}

コードが長くなるので順に見ていきましょう。まずはGreetingItemとGreetingListです。

class GreetingItem extends React.Component {
  render() {
    return (
      <li>Hello {this.props.name}</li>
    );
  }
}

class GreetingList extends React.Component {
  render() {
    var greetingItems = this.props.names.map(function(name, i){
        return <GreetingItem name={name} key={i} />;
    });

    return (
      <div>
        <h1>Welcome to Webz</h1>
        <ul>{greetingItems}</ul>
      </div>
    );
  }
}

GreetingItem、GreetingListについては以前に作成した内容と同じです。GreetingListのnamesプロパティに名前の配列を設定することで、個々の名前が子要素のGreetingItemのnameプロパティに設定されます。

つづいてEchoコンポーネントです。

class Echo extends React.Component {
  constructor(props) {
    super(props);
    // bind this
    this.echo = this.echo.bind(this);
    this.isEnterKey = this.isEnterKey.bind(this);
  }

  echo(e){
    this.props.onChange(e.target.value);
  }

  isEnterKey(e){
    if (e.keyCode == 13) {
      this.props.onSave(e.target.value);
    }
  }

  render() {
    return (
      <div>
        <h3>Please type your name.</h3>
        <input type="text" onChange={this.echo} onKeyDown={this.isEnterKey} value={this.props.name}/>
        <h3>{this.props.name}</h3>
      </div>
    );
  }
}

Echoコンポーネントは以前に作成したものと以下の点で異なります。

  1. ステートnameではなく、プロパティnameを使用している
  2. echoメソッドの実装でステートの更新ではなく、onChangeプロパテイ(関数)を呼び出している
  3. onKeyDownイベントハンドラでisEnterKeyメソッドを呼び出している

1. ステートnameではなく、プロパティnameを使用している

Reactで、複合コンポーネントを作成する場合、可能な限りステートの管理は親コンポーネントで管理するようにします。

  • Welcome
    • GreetingList
      • GreetingItem(*)
    • Echo

上記の場合、ステートはWelcomeコンポーネントで管理すべきです。従って入力中の名前を示すnameプロパティをWelcomeコンポーネントで定義し、代わりにEchoコンポーネントには、Welcomeコンポーネントとの外部インタフェースとなるnameプロパティを用意します。親コンポーネントのステートの変更をnameプロパティ経由で受け取るようにします。

render() {
  return (
    <div>
      <h3>Please type your name.</h3>
      <input type="text" onChange={this.echo} onKeyDown={this.isEnterKey} value={this.props.name}/>
      <h3>{this.props.name}</h3>
    </div>
  );
}

2. echoメソッドの実装でステートの更新ではなく、onChangeプロパテイ(関数)を呼び出している

Echoコンポーネントからnameステートを排除したので、echoメソッドの実装は次のようにonChangeプロパティを呼び出すようにします。

echo(e){
  this.props.onChange(e.target.value);
}

Echoコンポーネントを利用する親コンポーネント(今回の場合Welcomeコンポーネント)では次のようにプロパティを指定します。

<Echo name={this.state.name} onChange={this.foo} onSave={this.bar}/>

この場合、onChangeプロパティにWelcomeコンポーネントで指定したfooメソッドを指定してます。結果として、EchoコンポーネントでonChangeイベントが発生するとこのfooメソッドが呼ばれることになります。

3. onKeyDownイベントハンドラでisEnterKeyメソッドを呼び出している

onKeyDownイベントハンドラのisEnterKeyメソッドは次のようになっています。

isEnterKey(e){
  if (e.keyCode == 13) {
    this.props.onSave(e.target.value);
  }
}

キーコード:13とはEnterキーを意味しています。つまり、Enterキーが入力された場合、onSaveプロパティ(関数)を呼び出すようにしています。

たとえば、以下のようにEchoコンポーネントを定義しとしましょう。

<Echo name={this.state.name} onChange={this.foo} onSave={this.bar}/>

Enterキークリック時に、onSaveプロパティで指定されたbarメソッドが呼び出されることになります。

さいごに親コンポーネントとなるWelcomeのコンポーネント仕様を実装します。

class Welcome extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      names: this.props.names,
      name: ""
    };
    // bind this
    this.save = this.save.bind(this);
    this.echo = this.echo.bind(this);
  }

  save(completeName){
    var names = this.state.names.concat(completeName);
    this.setState({
      names: names,
      name: ""
    });
  }

  echo(incompleteName){
    this.setState({name: incompleteName});
  }

  render(){
    return(
      <div>
        <GreetingList names={this.state.names} />
        <Echo name={this.state.name} onChange={this.echo} onSave={this.save}/>
      </div>
    );
  }
}

constructorで初期ステートを指定します。ステートはnames配列と、name文字列の2つです。namesステートはGreetingListコンポーネントのnamesプロパティに指定し、nameステートはEchoコンポーネントのnameプロパティに指定します。

echoメソッド、saveメソッドはステートを更新します。これらのメソッドはEchoコンポーネントイベントハンドラに指定しているので、Echoコンポーネントにおいて、イベントが発生時するとコールバックされます。

renderメソッドではGreetingListと、Echoコンポーネントレンダリングしています。renderメソッドは単一のコンポーネントを返す必要があるので、divタグでラップしています。

3. コンポーネントクラスをレンダリング

作成したコンポーネントクラス(Welcome)を画面にレンダリングします。

var names = ["Murayama", "Takahashi", "Sanada"];
ReactDOM.render(
  <Welcome names={names} />,
  document.getElementById('example')
);

Welcomeコンポーネントのnamesプロパティに3件の名前を指定します。こうすることで、画面描画時の初期値として表示されます。

ここまでの作業をまとめると次のようになります。

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Hello React 05</title>
  <script src="https://unpkg.com/react@15.6.1/dist/react.js" charset="utf-8"></script>
  <script src="https://unpkg.com/react-dom@15.6.1/dist/react-dom.js" charset="utf-8"></script>
  <script src="https://unpkg.com/babel-standalone@6.15.0/babel.js"></script>
</head>
<body>
  <div id="example"></div>
  <script type="text/babel">
  class GreetingItem extends React.Component {
    render() {
      return (
        <li>Hello {this.props.name}</li>
      );
    }
  }

  class GreetingList extends React.Component {
    render() {
      var greetingItems = this.props.names.map(function(name, i){
          return <GreetingItem name={name} key={i} />;
      });

      return (
        <div>
          <h1>Welcome to Webz</h1>
          <ul>{greetingItems}</ul>
        </div>
      );
    }
  }

  class Echo extends React.Component {
    constructor(props) {
      super(props);
      // bind this
      this.echo = this.echo.bind(this);
      this.isEnterKey = this.isEnterKey.bind(this);
    }

    echo(e){
      this.props.onChange(e.target.value);
    }

    isEnterKey(e){
      if (e.keyCode == 13) {
        this.props.onSave(e.target.value);
      }
    }

    render() {
      return (
        <div>
          <h3>Please type your name.</h3>
          <input type="text" onChange={this.echo} onKeyDown={this.isEnterKey} value={this.props.name}/>
          <h3>{this.props.name}</h3>
        </div>
      );
    }
  }

  class Welcome extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
        names: this.props.names,
        name: ""
      };
      // bind this
      this.save = this.save.bind(this);
      this.echo = this.echo.bind(this);
    }

    save(completeName){
      var names = this.state.names.concat(completeName);
      this.setState({
        names: names,
        name: ""
      });
    }

    echo(incompleteName){
      this.setState({name: incompleteName});
    }

    render(){
      return(
        <div>
          <GreetingList names={this.state.names} />
          <Echo name={this.state.name} onChange={this.echo} onSave={this.save}/>
        </div>
      );
    }
  }

  var names = ["Murayama", "Takahashi", "Sanada"];
  ReactDOM.render(
    <Welcome names={names} />,
    document.getElementById('example')
  );
  </script>
</body>
</html>

Reactだけ学ぶハンズオン 4/5

Part4 Echo - ハンズオン

ここでは入力した内容を表示するReactアプリケーションを作成します。

20170915200536

開発は以下の手順で進めます。

  1. ライブラリの設定
  2. コンポーネント仕様を定義
  3. コンポーネントクラスをレンダリング

1. ライブラリの設定

titleタグ以外は前章と同じです。ファイル名は04_echo.htmlという名前で保存しておきます。

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Hello React 04</title>
  <script src="https://unpkg.com/react@15.6.1/dist/react.js" charset="utf-8"></script>
  <script src="https://unpkg.com/react-dom@15.6.1/dist/react-dom.js" charset="utf-8"></script>
  <script src="https://unpkg.com/babel-standalone@6.15.0/babel.js"></script>
</head>
<body>
  <div id="example"></div>
  <script type="text/babel">
  </script>
</body>
</html>

2. コンポーネント仕様を定義

ここでは画面の入力を受け付けるテキストボックスと、入力された名前を表示する領域を持ったとEchoコンポーネントクラスを作成します。

Echoコンポーネントの仕様は以下のとおりです。

class Echo extends React.Component {
  constructor(props) {
    super(props);
    this.state = {name: ""};
    // bind this
    this.echo = this.echo.bind(this);
  }

  echo(e){
    this.setState({name: e.target.value});
  }

  render() {
    return (
      <div>
        <h1>Welcome to WEBZ.</h1>
        <h3>Please type your name.</h3>
        <input type="text" onChange={this.echo} />
        <h3>{this.state.name}</h3>
      </div>
    );
  }
}

renderメソッド以外にconstructor、echoメソッドの2つが追加されています。constructorの説明に入る前にReactのステートについて学習しておきましょう。

Reactにはステートという仕組みがあります。ステートとはコンポーネントの状態を表すものです。上記のEchoコンポーネントには「(入力された)名前」を示すnameというステートがあります。Reactのコンポーネントはステートの内容が更新されると自動的に再描画(renderメソッド呼び出し)されるようになっています。

constructorはReactコンポーネントのライフサイクルメソッドの1つで、コンポーネントインスタンスの生成時に呼び出されます。constructorでステートの初期値を設定できます。

constructor(props) {
  super(props);
  this.state = {name: ""};
  // bind this
  this.echo = this.echo.bind(this);
}

上記のコードではnameステートの初期値を空文字で設定しています。

this.echo = this.echo.bind(this); は後の echoメソッド を利用できるようにしています。

つづいてechoメソッドを見てみましょう。

echo(e){
  this.setState({name: e.target.value});
}

echoメソッドはReactの仕組みに依存したものではなく、アプリケーション独自のメソッドです。echoメソッドはrenderメソッドの中でinputタグのonChangeイベントハンドラに関連付けられています。

<input type="text" onChange={this.echo} />

これによって、テキストボックスの値に変化が生じるとechoメソッドが呼び出されるようになります。echoメソッドの中では、コンポーネントのステートを更新するためにsetStateメソッドを呼び出しています。Reactは内部で仮想DOMによってコンポーネントを管理しているため、ステートを更新する場合、必ずsetStateメソッドを使用する必要があります。*1

echoメソッドによってステートが更新されるとコンポーネントのrenderメソッドがReactによって呼び出されます。

render() {
  return (
    <div>
      <h1>Welcome to WEBZ.</h1>
      <h3>Please type your name.</h3>
      <input type="text" onChange={this.echo} />
      <h3>{this.state.name}</h3>
    </div>
  );
}

これによってテキストボックスに入力した内容が即座に画面に表示されるようになります。

3. コンポーネントクラスをレンダリング

作成したコンポーネントクラス(Echo)を画面にレンダリングします。

ReactDOM.render(
  <Echo />,
  document.getElementById('example')
);

Echoコンポーネントにプロパティの指定はありません。

ここまでの作業をまとめると次のようになります。

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Hello React 04</title>
  <script src="https://unpkg.com/react@15.6.1/dist/react.js" charset="utf-8"></script>
  <script src="https://unpkg.com/react-dom@15.6.1/dist/react-dom.js" charset="utf-8"></script>
  <script src="https://unpkg.com/babel-standalone@6.15.0/babel.js"></script>
</head>
<body>
  <div id="example"></div>
  <script type="text/babel">

  class Echo extends React.Component {
    constructor(props) {
      super(props);
      this.state = {name: ""};
      // bind this
      this.echo = this.echo.bind(this);
    }

    echo(e){
      this.setState({name: e.target.value});
    }

    render() {
      return (
        <div>
          <h1>Welcome to WEBZ.</h1>
          <h3>Please type your name.</h3>
          <input type="text" onChange={this.echo} />
          <h3>{this.state.name}</h3>
        </div>
      );
    }
  }

  ReactDOM.render(
    <Echo />,
    document.getElementById('example')
  );
  </script>
</body>
</html>

*1:this.state.name = e.target.value; のように記述してはいけません。

Reactだけ学ぶハンズオン 3/5

Part3 GreetingList - ハンズオン

ここでは次のようなメッセージ一覧を表示するReactアプリケーションを作成します。

20170915200541

開発は以下の手順で進めます。

  1. ライブラリの設定
  2. コンポーネント仕様を定義
  3. コンポーネントクラスをレンダリング

1. ライブラリの設定

titleタグ以外は前章と同じです。ファイル名は03_greeting_list.htmlという名前で保存しておきます。

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Hello React 03</title>
  <script src="https://unpkg.com/react@15.6.1/dist/react.js" charset="utf-8"></script>
  <script src="https://unpkg.com/react-dom@15.6.1/dist/react-dom.js" charset="utf-8"></script>
  <script src="https://unpkg.com/babel-standalone@6.15.0/babel.js"></script>
</head>
<body>
  <div id="example"></div>
  <script type="text/babel">
  </script>
</body>
</html>

2. コンポーネント仕様を定義

Reactのコンポーネントクラスを定義するために、コンポーネント仕様を作成します。*1ここではHelloと挨拶するGreetingItemクラスと、複数のGreetingItemを管理するGreetingListクラスを定義します。

GreetingItemクラスは以下のとおりです。

class GreetingItem extends React.Component {
  render() {
    return (
      <li>Hello {this.props.name}</li>
    );
  }
}

前章で作成したGreetingクラスとほとんど同じです。nameプロパティの内容をレンダリングします。

続いてGreetingListクラスです。

class GreetingList extends React.Component {
  render() {
    var greetingItems = this.props.names.map(function(name, i){
        return <GreetingItem name={name} key={i} />;
    });

    return (
      <div>
        <h1>Welcome to Webz</h1>
        <ul>{greetingItems}</ul>
      </div>
    );
  }
}

GreetingListコンポーネントはnamesプロパティから名前の配列を受け取ります。実際の値の受け渡しは後のrenderフェーズで指定します。

renderメソッドではnamesプロパティをループして、JSXを使ってGreetingItem要素を定義しています。Reactは仮想DOMを使って要素を管理しているので、各要素にはkey属性を指定して一意な値を定義する必要があります。

3. コンポーネントクラスをレンダリング

作成したコンポーネントクラス(GreetingList)を画面にレンダリングします。GreetingListコンポーネントにnamesプロパティを指定している点を確認しておいてください。

var names = ["Murayama", "Takahashi", "Sanada"];
ReactDOM.render(
  <GreetingList names={names} />,
  document.getElementById('example')
);

ここまでの作業をまとめると次のようになります。

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Hello React 03</title>
  <script src="https://unpkg.com/react@15.6.1/dist/react.js" charset="utf-8"></script>
  <script src="https://unpkg.com/react-dom@15.6.1/dist/react-dom.js" charset="utf-8"></script>
  <script src="https://unpkg.com/babel-standalone@6.15.0/babel.js"></script>
</head>
<body>
  <div id="example"></div>
  <script type="text/babel">
  class GreetingItem extends React.Component {
    render() {
      return (
        <li>Hello {this.props.name}</li>
      );
    }
  }

  class GreetingList extends React.Component {
    render() {
      var greetingItems = this.props.names.map(function(name, i){
          return <GreetingItem name={name} key={i} />;
      });

      return (
        <div>
          <h1>Welcome to Webz</h1>
          <ul>{greetingItems}</ul>
        </div>
      );
    }
  }

  var names = ["Murayama", "Takahashi", "Sanada"];
  ReactDOM.render(
    <GreetingList names={names} />,
    document.getElementById('example')
  );
  </script>
</body>
</html>

*1:コンポーネントクラスを作成します。でいいような気が。

Reactだけ学ぶハンズオン 2/5

Part2 Greeting - ハンズオン

ここでは次のようなメッセージを表示するReactアプリケーションを作成します。*1

20170915200544

開発は以下の手順で進めます。

  1. ライブラリの設定
  2. コンポーネント仕様を定義
  3. コンポーネントクラスをレンダリング

1. ライブラリの設定

titleタグ以外は前章と同じです。ファイル名は02_greeting.htmlという名前で保存しておきます。

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Hello React 02</title>
  <script src="https://unpkg.com/react@15.6.1/dist/react.js" charset="utf-8"></script>
  <script src="https://unpkg.com/react-dom@15.6.1/dist/react-dom.js" charset="utf-8"></script>
  <script src="https://unpkg.com/babel-standalone@6.15.0/babel.js"></script>
</head>
<body>
  <div id="example"></div>
  <script type="text/babel">
  </script>
</body>
</html>

2. コンポーネント仕様を定義

Reactのコンポーネントクラスを定義するために、コンポーネント仕様を作成します。

class Greeting extends React.Component {
  render() {
    return (
      <div>
        <h1>Welcome to Webz</h1>
        <h2>Hello {this.props.name}</h2>
      </div>
    );
  }
}

renderメソッドではJSXを使ってコンポーネントを定義していますが、h2タグの中で{this.props.name}を指定しています。これはReactのプロパティという仕組みを使っています。プロパティとはReactコンポーネントの外部インタフェースです。ここでは外部から指定されたnameプロパティを表示するようにしています。nameプロパティの指定は、後のレンダリング時に指定します。

3. コンポーネントクラスをレンダリング

作成したコンポーネントクラス(Greeting)を画面にレンダリングします。前章とほとんど同じですが、Greetingコンポーネントにnameプロパティを指定している点を確認しておいてください。

var name = "Murayama";
ReactDOM.render(
  <Greeting name={name} />,
  document.getElementById('example')
);

ここまでの作業をまとめると次のようになります。

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Hello React 02</title>
  <script src="https://unpkg.com/react@15.6.1/dist/react.js" charset="utf-8"></script>
  <script src="https://unpkg.com/react-dom@15.6.1/dist/react-dom.js" charset="utf-8"></script>
  <script src="https://unpkg.com/babel-standalone@6.15.0/babel.js"></script>
</head>
<body>
  <div id="example"></div>
  <script type="text/babel">
  class Greeting extends React.Component {
    render() {
      return (
        <div>
          <h1>Welcome to Webz</h1>
          <h2>Hello {this.props.name}</h2>
        </div>
      );
    }
  }

  var name = "Murayama";
  ReactDOM.render(
    <Greeting name={name} />,
    document.getElementById('example')
  );
  </script>
</body>
</html>

*1:Webzてのは勉強会(コミュニティ)の名前です。気にせずに。。