
今回は学習中のReactでTodoアプリケーションの作成をしていきたいと思います。
余談ですが、Reactのロゴってカッコいいですよね。僕は好きです。
目次
実装機能
・ タスクの登録
・ タスクの削除
Reactアプリケーションの作成
※Nodeのインストール方法については今回は記載いたしません。
$ npx create-react-app todo-app
$ cd todo-app
$ npm start

` http://localhost:3000`にアクセスし、こちらの画面がブラウザ上で表示されていれば、成功です。
Reactコンポーネント
Reactでは細かなUIをコンポーネント単位で管理することができ、それらを組み合わせ開発を行うことで、保守性の高いアプリケーションを実現することができます。
先ほど、作成したアプリケーションのsrcディレクトリ配下のApp.jsファイルをみていきます。
import React from 'react';
import logo from './logo.svg';
import './App.css';
function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}
export default App;
こちらのファイルではAppというコンポーネントを関数にて定義しています。
コンポーネントの定義には、クラスコンポーネントと関数コンポーネントの2つの方法で定義することができます。
クラスコンポーネントでは、内部に状態(state)を持つことができたり、ライフサイクルメソッドの使用ができたりします。
関数コンポーネントでは、stateやライフサイクルメソッドの使用はできず、ざっくりいうとクラスコンポーネントのrender部分のみ書いてるようなイメージになります。その分、簡潔にコンポーネントの定義を行うことができます。
両者とも、コンポーネント間での情報を受け渡すことができるpropsを扱うことができるので状況に応じて使い分けていきましょう。
コンポネーネント・ライフサイクルメソッドについての詳細を知りたい方は、下記をご覧ください。
・コンポーネントと props
・state とライフサイクル
ファイルの構成
今回は、以下のファイル構成で作成していきます。
src/
  |-- App.js
  |-- index.js
  |-- components/
    |-- List.js
    |-- Form.js
タスクの登録
まず、App.jsにてAppコンポーネントの中身を変更していきます。今回はタスクの登録するための、stateのvalueとtodosをAppコンポーネント内で管理していきたいので、クラスコンポーネントで定義します。
App.js
import React from 'react';
import Form from './components/Form.js'   //Formコンポーネントの呼び出し
class App extends React.Component {
  constructor(props){
    super(props)
    this.state = {
      value: '',
      todos: [],
    }
  }
  handleChange = (e) => {
    this.setState ({ value : e.target.value })  //入力された文字
  }
  handleSubmit = (e) => {
    e.preventDefault();
    if(this.state.value === '') return  //空文字の登録を不可にする
    this.state.todos.push(this.state.value)  //todosにvalueを追加
    this.setState({  //setState()内でstateの値を変更
      todos: this.state.todos,
      value: '',  //フォームに入力されている文字を空にする
    })
  }
  render(){
    return(
      <React.Fragment>
        <Form   //Formコンポーネントに関数とstateを渡す
          handleChange={this.handleChange}
          handleSubmit={this.handleSubmit}
          value={this.state.value}
        />
      </React.Fragment>
    )
  }
}
export default App;
Form.js
import React from 'react';
const Form = props => {   //引数でAppコンポーネントからpropsを受け取る。
  return (
    <form onSubmit={props.handleSubmit}>
      <input
        type="text"
        onChange={props.handleChange}
        value={props.value}
      />
      <button type="submit">Add</button>
    </form>
  )
}
export default Form;
今回は、AppコンポーネントからFormコンポーネントに下記の3つを渡しています。
 <Form
    handleChange={this.handleChange}
    handleSubmit={this.handleSubmit}
    value={this.state.value}
  />
propsの確認はchormeの拡張機能のReact Developer Tools
をインストールすると手軽に確認することができます。
FormコンポーネントにhandleChangeとhandleSubmitとvalueが渡されていることが確認できます。

登録したタスクの表示と削除
Appコンポーネント内で削除機能のhandleRemoveを作成し、todosと一緒にListコンポーネントに渡してあげます。
App.js
import React from 'react';
import Form from './components/Form.js'
import List from './components/List.js'   //Listコンポーネントの呼び出し
class App extends React.Component {
  constructor(props){
    super(props)
    this.state = {
      value: '',
      todos: [],
    }
  }
  handleChange = (e) => {
    this.setState ({ value : e.target.value })
  }
  handleSubmit = (e) => {
    e.preventDefault();
    if(this.state.value === '') return
    this.state.todos.push(this.state.value)
    this.setState({
      todos: this.state.todos,
      value: '',
    })
  }
  handleRemove = (i) => {   //引数でiを受け取る
    this.state.todos.splice(i,1)  //i番目の要素を削除する
    this.setState({
      todos: this.state.todos
    })
  }
  render(){
    return(
      <React.Fragment>
        <Form
          handleChange={this.handleChange}
          handleSubmit={this.handleSubmit}
          value={this.state.value}
        />
        <List   //ListコンポーネントにtodosとhandleRemoveを渡す。
          todos={this.state.todos}
          handleRemove={this.handleRemove}
        />
      </React.Fragment>
    )
  }
}
export default App;
List.js
Listコンポーネント内で受け取ったtodosを、mapメソッドにて展開します。その際に必ずkeyを持たせてあげることに注意してください。
import React from 'react';
const List = props => {
  return (
    <ul>
      {props.todos.map((todo,i) => ( //受け取ったtodosをmapメソッドにて展開
        <li key={i}>
          {todo}
          <button onClick={() => props.handleRemove(i)}>Delete</button> //引数で削除したいタスクの番号(i)を渡す
        </li>
      ))}
    </ul>
  )
}
export default List;
こちらが完成イメージになります。

まとめ
今回は、Reactの基本であるコンポーネント、state、propsを用いてTodoアプリケーションの作成しました。
少しでも参考にしていただければ、幸いです。

