はじめてのReact #21「ToDoアプリを作る」 中編

  • このエントリーをはてなブックマークに追加
  • LINEで送る

前回に引き続き今回もToDoアプリを作っていきます。目標としてはフォームの使い勝手を向上させつつToDoの削除に対応するところまでとなります。

フォームを改良する

Submitイベントに対応

現状、登録フォームのテキストボックスに内容を入力しエンターキーを押した瞬間、再読込されてしまいます。これを防ぐには、formタグにonSubmitイベントを定義してあげればOK。今回はエンターキーを押すと確認用のダイアログを表示し、OKボタンが押されれば追加処理を行う形に変更しました。

src/todocreate.jsを以下のように変更します。

import React, { Component } from 'react';

class ToDoCreate extends Component {
  constructor(props){
    super(props);
    this.state = {
      newtodo: ""
    };

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

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

  handleSubmit(e){
    let newtodo = this.state.newtodo;
    if(newtodo !== "" && window.confirm('本当に登録しますか?')){
      this.props.onClick(newtodo);
      this.setState({newtodo:""});
    }
    e.preventDefault();
  }

  render(){
    return(
      <form onSubmit={this.handleSubmit}>
        <input type="text" value={this.state.newtodo} onChange={this.handleChange}/>
        <button>追加</button>
      </form>
    );
  }
}

export default ToDoCreate;

注意すべき点としてはconfirm()ではなく、window.confirm()とする必要があるところでしょうか。

Validationを行う

もう一つの問題点として、テキストボックスが空でも登録されている点ですね。これも直して置きます。src/todocreate.jsのhandleSubmit()を以下のように変更しました。空文字列または2文字未満であれば何もしません。

  handleSubmit(e){
    e.preventDefault();

    let newtodo = this.state.newtodo;
    if(newtodo === "" || newtodo.length < 2){
      return(false);
    }

    if(newtodo !== "" && window.confirm('本当に登録しますか?')){
      this.props.onClick(newtodo);
      this.setState({newtodo:""});
    }
  }

テキストボックスにfocusする

ToDoを入力する際にわざわざテキストボックスをクリックするのも面倒なので、ページが読み込まれたと同時にfocusをしてあげます。src/todocreate.jsを以下のように変更します。

import ReactDOM from 'react-dom';  //追加

class ToDoCreate extends Component {
  // (snip)

  componentDidMount(){
    ReactDOM.findDOMNode(this.refs.newtodo).focus();
  }

  // (snip)

  render(){
    return(
      <form onSubmit={this.handleSubmit}>
        <input type="text" ref="newtodo" value={this.state.newtodo} onChange={this.handleChange}/>
        <button>追加</button>
      </form>
    );
  }
}

上記は変更した部分だけを抜き出しています。

まずReactDOMの機能を利用しますので新たにimportしました。
componentDidMount()はLifeCycleの機能。ComponentがDOMツリーに追加された瞬間に呼び出されます。ここで単純にfocus()メソッドを実行してあげればよいのですが、問題はどうやってテキストボックスを特定するかです。

今回はテキストボックスに<input type="text" ref="newtodo">といった形でref属性を追加しました。この属性をつけておくとReactから簡単に参照することができるようになります。この場合だとthis.ref.newtodoですね。

ReactDOM.findDOMNode()は最終的にDOMオブジェクトを返却しますので、これでテキストボックスを検索し、戻り値のDOMオブジェクトに対してfocus()を実行しているといます。

Lifecycleについては過去の記事を参照してください。
[blogcard url=”https://blog.katsubemakito.net/react/react1st-4-lifecycle”%5D

- Sponsored Link -

ToDoの「削除」に対応

todo.js

handleRemove()を追加し、render()<ToDoList>へ渡しています。

最終的に「削除」ボタンを押すと handleRemove() が実行されるのですがこれまでとちょっと変わった引数の取り出し方をしていますが、これは後述します。またfilter()は配列内から必要な要素だけを取り出す動きをするJavaScriptのメソッドになります。

class ToDo extends Component {
  // (snip)

  handleRemove(e){
    let cur  = this.state.todo;
    let id   = Number( e.currentTarget.getAttribute("data-id") );
    let todo = cur.filter( i => i.id !== id );

    this.setState({
      todo: todo
    });
  }

  render() {
    return(
      <div>
        <ToDoCreate onClick={this.handleClick} />
        <ToDoList data={this.state.todo} remove={this.handleRemove}/>
      </div>
    );
  }
}

todolist.js

<ToDoItem>を生成する際に、ToDoComponentのhandleRemove()への参照をそのまま渡す処理を追加しています。

      return(
        <ul className="todolist">{
          data.map( i => <ToDoItem key={i.id} item={i} remove={this.props.remove} /> )
        }</ul>
      );

todoitem.js

タスクを表示すると同時に削除ボタンを追加しています。onClickでToDoComponentのhandleRemoveが呼ばれます。

    return(
      <li key={id}>
        {name} 
        <button type="button" data-id={id} onClick={this.props.remove}>✖</button>
      </li>
    );

ここではHTMLのカスタムデータ属性を利用しています。handleRemove()ではこのdata-id属性をe.currentTarget.getAttribute("data-id")として読み込んで利用します。これまでのサンプルと同様に、onClickでToDoItemComponent内のメソッドを呼び出し、そこでToDoComponentのhandleRemoveを呼び出す形でももちろん動作します。お好きな方でどうぞ。

実行結果

ここまでのソースコードは以下になります。
[blogcard url=”https://github.com/katsube/rtodo/tree/4ebd4eef58c28d4d3e25e420be9579f669138db5″%5D

続く

次回に続きます。
[blogcard url=”https://blog.katsubemakito.net/react/react1st-22-todo3″%5D

- Sponsored Link -

同じカテゴリの記事

Donate

投げ銭お待ちしております!

BTC3A9nH1j7qQdKrSTrmnEdweo6zPqpHBmkxC
ETH0x1aE0541198D1F9f2908a25C35032A473e74D3731
XPXaQ9zv65F9ovfoMBrFGiPRG47aSHFhy8SX
MONAMTKgzSiS5BDueZkRCHySih24TGFwHThaDQ (MonaCoin)
ZNYZhnpf4RFYVQTAQiyoJg9dGoeC4bgT3BoSy (BitZeny)

ご質問やリクエストなどお気軽に。メールアドレスの入力は任意です。書き込みが反映されるまで時間がかかります。

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください