React.jsで簡易todo listを作ってみた(codepen, github)

プロローグ

React.js公式サイト(英語)

一通りReact.jsのDocumentのinstallationとquick startを実践しながら勉強しました。
実際に自分どこまで理解できたのか知りたいので、簡単なWeb applicationを作ってみようかなと。
初心者向けの課題によく出て来るtodo listを選びました。

この記事の最後に完成したサンプル(codepen)とgithubのリンク貼り付けておりますので、ご参考にしていただければ幸いです。

要件定義

簡易バージョンなので、最低限のものだけ作りたいと思います。
- 書き込める場所
- 保存するボタン
- Todo Listを表示させる
(修正不可、削除不可)

ゴール:

完成したtodo list

参考サイト(英語)

1. Simple React todo list – Agata Krzywda – Medium

今回の勉強記録はこの記事の内容を整理しつつ、公式サイトと見比べながら書き換えたものになります。

スタート

(ターミナルで)
tutorialでインストールしたReactのcreate-react-appコマンドを使って、todolistフォルダを作成します。

$ create-react-app todolist

フォルダ内に移動します。

$ cd todolist
$ npm start

自動的にローカルでブラウザ立ち上がり、React.jsページのデフォルトの状態が表示されます。

そして、エディターでフォルダを開くと、構造は
-node_modules/
-public/
-src/
-package-lock.json
-package.json
-README.md
になっています。

/src/app.js
/src/index.js
デフォルトの書き方は主に記述内容はapp.js内で書いて、index.js内でapp.jsを呼び込んで、/public/index.html内で描きます。

実行されるものはindex.jsなので、今回はapp.jsを使わずに、index.jsだけ使いたいと思います。

import React from 'react';
import ReactDOM from 'react-dom';

ReactDOM.render(<App />, document.getElementById('root'));
registerServiceWorker();

いらないものを削除して、これだけ残します。
そして、app classをimportの後に追記します。
formを作って入れます。

import React from 'react';
import ReactDOM from 'react-dom';

class App extend React.Component {
    render() {
        return(
            <div>
                <form>
                    <input type="text" value="" />
                    <input type="submit" value="Submit" />
                </form>
            </div>
        );
    }
}

ReactDOM.render(<App />, document.getElementById('root'));
registerServiceWorker();

Appの構造を定義します。

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

そして、functionは2つあります。
onChangeはinput内に書いたら、inputのvalueに保存する→[term]
onSubmitは先ほど保存したvalueをstate内のitemsにパスする→[items]

constructor内でfunctionを結びついてから、functionを書きます。

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

        this.onChange = this.onChange.bind(this);
        this.onSubmit = this.onSubmit.bind(this);
    }

    onChange(e) {
        this.setState({
            term: e.target.value
        });
    }

    onSubmit(e) {
        e.preventDefault();
        this.setState({
            term: '',
            items: [...this.state.items, this.state.term]
        });
    }

...this.state.items
という書き方はquick start内には説明してなかったけど、advanced guide内にはありました。

JSX In Depth - React

すべての〇〇という意味です。ここはすべてのthis.state.itemsです。

そして、renderで書いてたform内のfunctionと繋げます。
formの書き方こちらを参照してます。

Forms - React

   render() {
        return (
            <div>
                <form onSubmit={this.onSubmit}>
                    <input type="text" value={this.state.term} onChange={this.onChange} />
                    <input type="submit" value="Submit" />
                </form>
            </div>
        );
    }

最後、todo listを表示するために、functionを作ります。
mapの書き方こちらを参照してます。

Lists and Keys - React

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

class App内のreturnをを追記して、this.state.itemsと繋げます。

   render() {
        return (
            <div>
                <form onSubmit={this.onSubmit}>
                    <input type="text" value={this.state.term} onChange={this.onChange} />
                    <input type="submit" value="Submit" />
                </form>
                <List items={this.state.items} />
            </div>
        );
    }

最終的にまとめてみると、こうなります。

import React from 'react';
import ReactDOM from 'react-dom';


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


class App extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            term: '',
            items: []
        };

        this.onChange = this.onChange.bind(this);
        this.onSubmit = this.onSubmit.bind(this);
    }

    onChange(e) {
        this.setState({
            term: e.target.value
        });
    }

    onSubmit(e) {
        e.preventDefault();
        this.setState({
            term: '',
            items: [...this.state.items, this.state.term]
        });
    }

    render() {
        return (
            <div>
                <form onSubmit={this.onSubmit}>
                    <input type="text" value={this.state.term} onChange={this.onChange} />
                    <input type="submit" value="Submit" />
                </form>
                <List items={this.state.items} />
            </div>
        );
    }
}


ReactDOM.render (
    <App />,
    document.getElementById('root')
);

ブラッシュアップ

テストで何件タスクを入れてみましたが、改善点を見つけました。
例えば、間違えてenter(return)を押したら(=submitボタンを押したら)、空白のままでリストに入っちゃうので、それをブロックしたいです。

最後に空白なら追加しないようにonSubmit functionに条件入れます。

   onSubmit(e) {
        e.preventDefault();
        if(this.state.term){
            this.setState({
                term: '',
                items: [...this.state.items, this.state.term]
            });
        }
    }

これで間違えて押しても追加されません!

Todo Listの完成体はこちらです!

(はじめてCodepenを導入してみました!)

See the Pen Todo list made by React.js by manmanrai (@manmanrai) on CodePen.

Githubソースコードアップしました。
ディレクトリやファイルほぼデフォルトのままです。手入れたファイルはindex.jsのみになってます。

github.com