1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

React TODOアプリ作成

Posted at

こちらの記事は以下の書籍を参考にアウトプットとして執筆しました
React入門 React・Reduxの導入からサーバサイドレンダリングによるUXの向上まで

TODOアプリに必要なコンポーネント

コンポーネント 説明
App 各コンポーネントのまとめ役。データ管理
TodoInput 入力フォームと登録ボタン
TdoItem 1つのTodo。タイトルと削除ボタンをもつ
TodoList Todoの一覧

Appコンポーネント

import React,{Component} from 'react'

これはどういう意味なのだろうか。
import X from Yならわかるが{}が出てきて,で区切られている

//デフォルトエクスポートはReactという名前で、
//また、Componentという名前付きエクスポートをインポートしている
import React,{Component} from 'react'

デフォルトエクスポートは1つのモジュールに1つ定義でき、
名前付きエクスポートは1つ以上定義できる。

import React,{Component} from 'react';
import TodoInput from './TodoInput';
import TodoList from './TodoList';

class App extends Component{
  render(){
    //TODO:後々stateで管理する
    const tasks=[
      {title:'Todo1つ目',id:0},
      {title:'Todo2つ目',id:1},
    ];
    return (
      <div>
        <h1>TODO App</h1>
        <TodoInput/>
        <TodoList tasks={tasks}/>
      </div>
    )
  }
}

参考:React入門 React・Reduxの導入からサーバサイドレンダリングによるUXの向上まで

このコードは'react'からデフォルトエクスポートのReactと名前付きエクスポートのComponentをインポートし、

Componentを継承したAppクラスを定義している。

Appクラスの中身を見てみると
renderメソッド一つだけを定義している。
このメソッドはJSXを返す。

TodoInputコンポーネント

App.jsを見てみるとTodoinputコンポーネントのjsファイルはApp.jsと同じディレクトリに作成するようだ

import React, { Component } from 'react';

class TodoInput extends Component {
    render() {
        return (
            <div>
                <input placeholder="新規TODOを入力" />
                <button>登録</button>
            </div>
        )
    }
}

export default TodoInput;

参考:React入門 React・Reduxの導入からサーバサイドレンダリングによるUXの向上まで

ここではTodoInputクラスを定義していて
renderメソッドを持っている

後はTodoInputをデフォルトエクスポートしている

TodoList

import React, { Component } from 'react';
import TodoItem from './TodoItem'

class TodoList extends Component {
    render() {
        //tasks内の各todoをTodoItemコンポーネントでエレメントにしている
        //list変数はTodoItemエレメントの配列が入っている
        const list = this.props.tasks.map(todo => {
            return <TodoItem {...todo} key={todo.id} />
        })
        return (
            <div>
                <ul>
                    {list}
                </ul>
            </div>
        )
    }
}

export default TodoList;

参考:React入門 React・Reduxの導入からサーバサイドレンダリングによるUXの向上まで

        const list = this.props.tasks.map(todo => {
            return <TodoItem {...todo} key={todo.id} />
        })

App.jsでReactコンポーネントを

<TodoList tasks={tasks}/>

と定義してい箇所があるため、TodoList.jsでの
this.props.tasksには

const tasks=[
      {title:'Todo1つ目',id:0},
      {title:'Todo2つ目',id:1},
    ];

が入る。

そしてこれをmapで処理して新しいlist配列を生成している。
よって<TodoItem {...todo} key={todo.id} />が展開されると以下のようになる

<TodoItem title='Todo1つ目' id=0 key=0 />
<TodoItem title='Todo2つ目' id=0 key=1 />

そしてTodoInHtemが入ったlist配列をrenderメソッドが返している。

TodoItem

import React from 'react'

function TodoItem(props) {
    return (
        <li>
            {props.title}
        </li>
    )
}
export default TodoItem;

参考:React入門 React・Reduxの導入からサーバサイドレンダリングによるUXの向上まで

state初期値

Appのtasksをstateで管理する。
初期値はconstructorで設定する

App.js
import React, { Component } from 'react';
import TodoInput from './TodoInput';
import TodoList from './TodoList';

class App extends Component {
  constructor(props) {
    super(props)
    this.state = {
      tasks: [
        {
          title: 'デフォルトTODO',
          id: 0,
        },
      ],
      uniqueId: 1,
    }
  }
  render() {
    return (
      <div>
        <h1>TODO App</h1>
        <TodoInput />
        <TodoList tasks={this.state.tasks} />
      </div>
    )
  }
}

stateは定義するためにconstructorで設定
以降変更するときはsetStateを使う
superでComponent側のconstructorでpropsを処理

addTodoメソッドの追加

新規TODOを追加できるようのメソッドを作成

App.js
  addTodo(title) {
    const { tasks, uniqueId, } = this.state;
    tasks.push({
      title, id: uniqueId
    })
    this.setState({
      tasks, uniqueId: uniqueId + 1
    })
  }

参考:React入門 React・Reduxの導入からサーバサイドレンダリングによるUXの向上まで

//これは分割をしている。
const { tasks, uniqueId, } = this.state;

//これは以下と同義
const tasks = this.state.tasks
const uniqueId = this.state.uniqueId
tasks.push({
      title, id: uniqueId
    })

これは省略されている。
titleはプロパティ名をtitleとして値を変数titleの値を設定している。

後はsetStateでstateに保存している。

このaddTodoをTodoInputで使うために渡す

<TodoInput addTodo={this.addTodo} />

最後にaddTodoメソッドで適切にstateを変更するために以下のコードを追記

App.js
constructor(props) {
   //中略
   this.addTodo=this.addTodo.bind(this)
  }

bindはすべてのfunctionオブジェクトが持っているメソッド

addTodoメソッドでのthisはAppコンポーネントのつもりで書いているが、実際このメソッドを実行するのは別のDOM、コンポーネントであるため、stateを持たないものもある。

これを書くことでaddTodoのなかのthisは常にAppインスタンスを指し、this.stateはAppコンポーネントのstateを参照する。

bindを使わない方法として、アロー演算子を使うなどの手法があるが、コンポーネントを渡すときに毎回アロー関数を書く必要があるなど、手間が増えるため、当面はbindを使っていったほうがいい

イベントハンドリング

TodoInputにはpropsとしてaddTodoが渡されていた

<TodoInput addTodo={this.addTodo} />

クリックするたびにaddTodoメソッドを呼ぶメソッドを新たに追加

import React, { Component } from 'react';

class TodoInput extends Component {
    constructor() {
        super(props)
        this.handleClick = this.handleClick.bind(this)
    }
    handleClick() {
        this.props.addTodo('新規TODO')
    }
    render() {
        return (
            <div>
                <input placeholder="新規TODOを入力" />
                <button onClic={this.handleClick}>登録</button>
            </div>
        )
    }
}

export default TodoInput;

参考:React入門 React・Reduxの導入からサーバサイドレンダリングによるUXの向上まで

またコンストラクタでbindしてhandleClickメソッドでのthisは常にTodoInputコンポーネントを指すことになった

button要素にonClick属性で関数を渡している。
これはブラウザのイベントと同じような感覚で引数も扱える。

from操作

Reactはフォーム入力もstateとして扱う。
フォーム入力はこのコンポーネントのみで利用するので(このコンポーネントってどこだよって読んでて思った)親コンポーネントのAppで定義する必要はない

次にstateとして持っている値をinput要素のvalueに設定
最後にユーザの入力ごとに実行され、その都度入力されている値をstateにセットするメソッドを書く

1
3
0

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
1
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?