LoginSignup
27
26

More than 5 years have passed since last update.

React 入門チュートリアル②

Posted at

一応この記事の続きです。React 入門チュートリアル①
react触ったことない方は①、stateとporpsにつまずいている方はこの記事からでも大丈夫だと思います。

今回は簡単なTODOリストアプリを作りながら、stateとporpsとカスタムコンポーネントの作成について理解してもらえればなと思います。

実際に作るのはこんな感じ
スクリーンショット 2017-01-02 22.18.23.png

今回の目標

  • stateとpropsの概念を理解する
  • カスタムコンポーネントの作成の仕方

用意するもの

いざ、実践

リストの部分を作る

リスト部分を作りながらpropsカスタムコンポーネントの作成について
説明しようと思います。

カスタムコンポーネント!!ていうとすごいように聞こえますが、オリジナルのコンポーネントという意味です。
それ以上でもそれ以下でもなくて、今回の例で言うとリストを表示する(配列からリストを作成する)コンポーネントを作成するて感じです。

では早速、<script type="text/babel"></script>内を編集していきます。

関数でカスタムコンポーネントを定義する

まずはjs(javascript)の関数で定義して、表示までやっていきます。

const TodoList = () => {
  return (
    <ul>
      <li>ほげ</li>
      <li>ほげ</li>
      <li>ほげ</li>
    </ul>
  );
}

ReactDOM.render(
  <TodoList />,
  document.getElementById('content')
);

新しいところは、カスタムコンポーネントはjsの関数できるということだけです。

少し補足すると、const TodoList = () => {}function TodoList () {}と同じ意味で、Reactコンポーネントは<ul></ul>とか<li></li>のJSXで書かれたHTMLを作成ものです。* React 入門チュートリアル①で詳しく説明してます。

これだと、表示するリストの内容が変えられないので、配列をこのTodoListコンポーネントに渡すとリスト化してくれるように改善しましょう。

propsで外から与えられた変数にアクセスする

ここで、propsmap()を使って編集すると

const items = ["hoge","hogehoge","fugaga"];

const TodoList = (props) => {
  return (
    <ul>
      {props.items.map((item, index) => (
        <li key={index}>{item}</li>
      ))}
    </ul>
  );
}

ReactDOM.render(
  <TodoList items={items} />,
  document.getElementById('content')
);

itemsTodoListコンポーネントに渡す配列を作成していて

map()の部分を少し補足すると

<ul>
  {items.map((item, index) => (
    <li key={index}>{item}</li>
  ))}
</ul>

# propsの部分を省きました

map()がわからない方はjsの内容になるのでググってもらって、
<li key={index}>{item}</li>keyはアイテムの変更の識別に必要なもので、
keyを設定しないと表示には成功しますが、コンソールに警告が出ます。

アイテムの削除や変更機能などをつけていくとエラーやバグの原因になると思うので、Reactで配列を扱うときはkeyを設定しましょう。
*keyについては他の記事で追記する予定

次にporpsの説明です。

const TodoList = (props) => {
  return (
    <ul>
      {props.items}
    </ul>
  );
}

ReactDOM.render(
  <TodoList items={変数} />,
  document.getElementById('content')
);

*propsに関連する部分だけ抽出したもの、多分動かない

「propsで外から与えられた変数にアクセスする」でわかる人もいると思いますが
<TodoList items={変数} />TodoListを呼び出す際にHTMLの属性の設定のように、変数を渡すことができて
const TodoList = (props) => {}のようにTodoList関数に引数を設定して
TodoList関数内では{props.items}で渡された変数にアクセスできます。

これであとはフォームを作成して、入力した内容を配列itemに追加するロジックを作れば完成です!

フォーム部分を作る

関数でカスタムコンポーネントを定義する

またもやカスタムコンポーネントの定義から、TodoList関数はそのままにして、以下のように編集します。

class TodoApp extends React.Component {
  render() {
    return (
      <div>
        <h3>TODOアプリ</h3>
        <form>
          <input/>
          <button>Add</button>
        </form>
      </div>
    );
  }
}


ReactDOM.render(
  <TodoApp />,
  document.getElementById('content')
);

ReactではES6のclass構文を使用して、コンポーネントを定義するほうがメジャーだと思います。class構文を使うことによって、class内で独自の変数stateを保持したり、メソッドを定義できるので、class構文のほうができる幅は広いです。

ではなぜ、TodoListは関数で定義したかというと、簡単に言うとclassを作るほどのコンポーネントでないからです。もちろんclassで作っても動作します。
propsしか使わない(関数ではstateは使用不可)ですし、将来的に関数で定義したほうが早く動作する可能性がある、シンプルにかけるので関数で定義しました。

説明するところがあるとしたら、classが呼び出されるとrenderメソッドreturn部分を返してくれるので、以前と同じく<TodoApp />という形で呼び出しができます。

 classにstate(ステータス)を持たせる

配列itemsを削除して、TodoAppを以下のように編集します。

class TodoApp extends React.Component {
  constructor(props) {
    super(props);
    this.state = {items: ["hoge","hogehoge","fugaga"]};
  }

  render() {
    return (
      <div>
        <h3>TODOアプリ</h3>
        <form>
          <input/>
          <button>Add</button>
        </form>
        <TodoList items={this.state.items} />
      </div>
    );
  }
}

これで、ブラウザを更新すると、フォームとリストが表示できるはずです。
ここでは、stateの設定と<TodoList />で前半で定義したコンポーネントを呼び出しています。

constructor(props) {
 super(props);
 this.state = {items: ["hoge","hogehoge","fugaga"]};
}

上の2行は構文で、stateの内容はthis.state = {items: ["hoge","hogehoge","fugaga"]};で設定しています。
そして設定した内容は{this.state.items}で呼出せます。

itemsの初期値は空配列にしたいので、this.state = {items: [ ]};に修正します。

 フォームに入力されたものを取得する

フォームに入力に入力されたもの、取得してtextというstate(ステータス)として保持させます。

まず、新しいstateを追加します。

constructor(props) {
  super(props);
  this.state = {items: [], text: ''};
}

次にinputタグのonChangeイベントを使って、ステータスtextを更新するhandleChangeメソッドを定義します。

render() {
    return (
      <div>
        <h3>TODOアプリ</h3>
        <form>
          <input onChange={this.handleChange.bind(this)} />
          <button>Add</button>
        </form>
        <TodoList items={this.state.items} />
      </div>
    );
  }

  handleChange(e) {
    this.setState({text: e.target.value});
  }
}

ここからはReactというよりかはjsの実装て感じですね。

ステータスを更新するにはsetState()メソッドを使用します。
setState({ステータス名: 更新する内容})のように、書きます。

少しだけ補足するとbind(this)の部分は

constructor(props) {
  super(props);
  this.handleChange = this.handleChange.bind(this);
  this.state = {items: [], text: ''};
}
省略
   <input onChange={this.handleChange} />

みたいな書き方が推奨されてます。できるだけruturn内をシンプルに保つためでしょうか。

実際にtextが更新されているかは、適当な場所に(h3タグの下とか)に<p>{this.state.text}</p>を追加して、実際に入力すれば確認してださい。

 エンターを押したら、入力内容をitemsに追加する

入力内容をitemsに追加するメソッドを定義します。
this.state.textで入力内容を取得して、setStateでitemsに追加して、更新という流れです。

handleSubmit(e) {
  e.preventDefault();
  const newItem = this.state.text;
  this.setState((prevState) => ({
    items: prevState.items.concat(newItem)
  }));
}

それをformタグのonSubmitイベントに割り当てます。

<form onSubmit={this.handleSubmit.bind(this)}>
  <input onChange={this.handleChange.bind(this)} />
  <button>Add</button>
</form>

これで、入力したものがリスト化されるはずです!!
実際に動かしてみましょう。

いよいよ最後です!
動かしてみると、フォーム入力したものが残ったままなので、handleSubmitメソッドが動く段階でついでにステータスtextを空の文字列に更新しましょう。
また、inputタグのvalue属性にこれを渡してあげないと見た目上は反映されないので編集してましょう。

ついでに全体のコードを載せるとこんな感じになると思います。

<script type="text/babel">
  class TodoApp extends React.Component {
    constructor(props) {
      super(props);
      this.state = {items: [], text: ''};
    }
    render() {
      return (
        <div>
          <h3>TODOアプリ</h3>
          <form onSubmit={this.handleSubmit.bind(this)}>
            <input onChange={this.handleChange.bind(this)} value={this.state.text} />
            <button>Add</button>
          </form>
          <TodoList items={this.state.items} />
        </div>
      );
    }

    handleChange(e) {
      this.setState({text: e.target.value});
    }

    handleSubmit(e) {
      e.preventDefault();
      const newItem = this.state.text;
      this.setState((prevState) => ({
        items: prevState.items.concat(newItem),
        text: ''
      }));
    }
  }


  const TodoList = (props) => {
    return (
      <ul>
        {props.items.map((item, index) => (
          <li key={index}>{item}</li>
        ))}
      </ul>
    );
  }

  ReactDOM.render(
    <TodoApp />,
    document.getElementById('content')
  );
</script>

おわり

疲れました。でも、ここまでくるとだいぶ作れるUIの幅が広がると思います。
自分はjsがちょっと怪しかったのです。何回もエラーを吐いて大変でしたが
なんとか完成してよかったです。
お疲れ様でした。

記事作成TODO

  • React 入門チュートリアル③
  • key(React)について
  • bind(this)
  • concat
27
26
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
27
26