Todoアプリ

目次

1. プロジェクトの作成

Macの場合ターミナルを起動し、プロジェクトを作成したいフォルダへ移動後、以下のコマンドを実行します。
その前にnodeが入っていることが前提です。コマンドで確認していきましょう。バージョンが表示されれば大丈夫です。

node -v

プロジェクトを作成するため、以下のコマンドを実行します。

npx create-react-app 任意のプロジェクト名

作成でできるまで、約5分程かかります。
なお、プロジェクト名には大文字を含めることはできません。

「Happy hacking!」と表示されれば完了です。

2. VS Code

2-1. サーバー起動と停止

VS Codeを開き、上部タブの「ターミナル」を選択後、「新しいターミナル」を選択します。
開いたVS Codeのターミナルで、サーバーを実行してみましょう

npm start

すると、ターミナル内にローカルのポート番号が表示されますので、ブラウザで確認してみましょう。
以下のように表示されればOKです。

なお、サーバーを停止するには、「controlキー」と「c」を同時押しです。

3. クリーニング

上記の画像のようにデフォルトで備わっていますが、開発上必要ないので、削除していきます。

App.js

import './App.css';

function App() {
  return (
    <div className="App">

    </div>
  );
}

export default App;

App.css内のコードも全て削除しておきましょう。

以下ファイルを削除

  • App.test.js
  • logo.svg
  • setupTests.js

4. 各コンポーネントを作成

コンポーネントを管理するため、srcフォルダの直下に「components」のフォルダを作成します。

4-1. タイトルコンポーネントの作成

作成したcomponentsフォルダに、「Title」ファイルを作成します。拡張子は「.jsx」とします。

Titleファイルに以下の雛形を記述していきます。
なお、プラグインをインストールしている場合は、「rafc」と入力すると、自動補完できます。

import React from 'react';

const Title = () => {
  return (
    <div>
      
    </div>
  )
};

export default Title;

return内のdivタグに画面に表示したい事を記述していきます。
ここでは「Todo管理」とします。

import React from 'react';

const Title = () => {
  return (
    <div>
      <h1>Todo管理</h1>
    </div>
  )
};

export default Title;

これでタイトルコンポーネントの作成が完了しましたので、これをAppファイルに反映していきます。
App.jsを開き、インポートします。

import Title from "./components/Title";

function App() {
  return (
    <div>

    </div>
  );
}

export default App;

次にdivタグ内にインポートしたTitleコンポーネントを使用します。

import Title from "./components/Title";

function App() {
  return (
    <div>
      <Title/>
    </div>
  );
}

export default App;

ここで画面を確認すると、タイトルコンポーネントが反映されています。

これで、タイトルコンポーネントの完成です。

4-2. todoを追加するコンポーネントの作成

次にtodoを追加するコンポーネントを作成していきます。
componentsフォルダに、「InputForm」ファイルを作成します。拡張子は「.jsx」です。雛形も入力します。

import React from 'react'

const InputForm = () => {
  return (
    <div>
      <form> //フォームタグ
        <input type="text"/> //入力できるボックス
        <button> //追加ボタン
            追加
        </button>
      </form>
    </div>
  )
};

export default InputForm;

これをAppファイルに反映していきます。
App.jsを開き、インポートします。

import Title from "./components/Title";
import InputForm from "./components/InputForm";

function App() {
  return (
    <div>
      <Title/>
      <InputForm/>
    </div>
  );
}

export default App;

4-3. todoのリストコンポーネントの作成

次にtodoのリストコンポーネントを作成していきます。
componentsフォルダに、「TodoList」ファイルを作成します。拡張子は「.jsx」です。雛形も入力します。

コードを追加していきます。

import React from 'react';

const TodoList = () => {
  return (
    <div>
        {/* todoをまとめたdiv */}
        <div>
            {/* todo */}
            <div>
                {/* todoのテキスト */}
                <div>
                    {/* テキストの文字 */}
                    <span>
                        テキスト文字のテスト
                    </span>
                </div>
            </div>
        </div>
    </div>
  )
};

export default TodoList;

これをAppファイルに反映していきます。
App.jsを開き、インポートします。

import Title from "./components/Title";
import InputForm from "./components/InputForm";
import TodoList from './components/TodoList';

function App() {
  return (
    <div>
      <Title/>
      <InputForm/>
      <TodoList/>
    </div>
  );
}

export default App;

次に追加機能として、追加されたtodoに対しての削除機能を実装していきます。

import React from 'react';

const TodoList = () => {
  return (
    <div>
        {/* todoをまとめたdiv */}
        <div>
            {/* todo */}
            <div>
                {/* todoのテキスト */}
                <div>
                    {/* テキストの文字 */}
                    <span>
                        テキスト文字のテスト
                    </span>
                </div>
                <div>
                    <button>削除</button>
                </div>
            </div>
        </div>
    </div>
  )
};

export default TodoList;

削除ボタンがtodoの下にあるので、todoの右隣に来るようにします。
cssを適用するため、className属性でdivタグに名前を付与します。

import React from 'react';

const TodoList = () => {
  return (
    <div>
        {/* todoをまとめたdiv */}
        <div>
            {/* todo */}
            <div className="todo">
                {/* todoのテキスト */}
                <div>
                    {/* テキストの文字 */}
                    <span>
                        テキスト文字のテスト
                    </span>
                </div>
                <div>
                    <button>削除</button>
                </div>
            </div>
        </div>
    </div>
  )
};

export default TodoList;

cssを記述するため、App.cssにコードを追加します。

.todo {
  display: flex;
}

App.jsにApp.cssをインポートします。

import './App.css';
import Title from "./components/Title";
import InputForm from "./components/InputForm";
import TodoList from './components/TodoList';

function App() {
  return (
    <div>
      <Title/>
      <InputForm/>
      <TodoList/>
    </div>
  );
}

export default App;

4-4. 追加ボタンを押下で、todoを追加していく機能の実装

todoを追加していく機能の考え方として、追加ボタンを押下するたびに、divタグのtodoを増やしていく感じです。

import React from 'react';

const TodoList = () => {
  return (
    <div>
        {/* todoをまとめたdiv */}
        <div>
            {/* todo */}
            <div className="todo">
                {/* todoのテキスト */}
                <div>
                    {/* テキストの文字 */}
                    <span>
                        テキスト文字のテスト
                    </span>
                </div>
                <div>
                    <button>削除</button>
                </div>
            </div>
            {/* todo */}
            <div className="todo">
                {/* todoのテキスト */}
                <div>
                    {/* テキストの文字 */}
                    <span>
                        テキスト文字のテスト
                    </span>
                </div>
                <div>
                    <button>削除</button>
                </div>
            </div>
        </div>
    </div>
  )
};

export default TodoList;

4-4-1.入力された文字情報を送る

InputForm.jsx

formタグから情報を送るように、onSubmitを追加します。

import React from 'react'

const InputForm = () => {
  return (
    <div>
      <form onSubmit={hundleSubmit}>
        <input type="text"/>
        <button>
            追加
        </button>
      </form>
    </div>
  )
};

export default InputForm;

この onSubmit の hundleSubmit で関数を定義します。

import React, { useState } from 'react'

const InputForm = () => {

  // 追加ボタンを押すと実行される関数
  const hundleSubmit = (e) => {
    // 再レンダリングを停止する
    e.preventDefault();
  }

  return (
    <div>
      <form onSubmit={hundleSubmit}>
        <input type="text"/>
        <button>
          追加
        </button>
      </form>
    </div>
  )
};

export default InputForm;

4-4-2. 送られたinputタグの情報を保管する

保管するには、useStateを使用します。

import React, { useState } from 'react'

const InputForm = () => {

  const { inputText, setInputText } = useState("");

  const hundleSubmit = (e) => {
    // 再レンダリングを停止する
    e.preventDefault();

  }

  const handleValue = (e) => {
    setInputText(e.target.value);  //useStateのset関数で保管
  }

  return (
    <div>
      <form onSubmit={hundleSubmit}>
        <input type="text" onChange={handleValue} />
        <button>
          追加
        </button>
      </form>
    </div>
  )
};

export default InputForm;

4-4-3. 保管された入力情報を送る機能の実装

inputText内に入力情報が保管されているので、App.jsに反映していきます。
propsにより、InputFormからAppに送ります。

App.js

import './App.css';
import { useState } from 'react'
import Title from "./components/Title";
import InputForm from "./components/InputForm";
import TodoList from './components/TodoList';

function App() {

  const {todoList, setTodoList} = useState([]);

  return (
    <div>
      <Title/>
      <InputForm todoList={todoList} setTodoList={setTodoList} />
      <TodoList/>
    </div>
  );
}

export default App;

InputForm.jsx

import React, { useState } from 'react'

const InputForm = ({ todoList, setTodoList }) => {

  const { inputText, setInputText } = useState("");

  const hundleSubmit = (e) => {
    // 再レンダリングを停止する
    e.preventDefault();

    //タスクを追加する
    setTodoList([
      ...todoList,  //スプレット構文により、配列の中に入れていく
      {
        text: inputText
      }
    ]);
  }

  const handleValue = (e) => {
    setInputText(e.target.value);
  }

  return (
    <div>
      <form onSubmit={hundleSubmit}>
        <input type="text" onChange={handleValue} />
        <button>
          追加
        </button>
      </form>
    </div>
  )
};

export default InputForm;

4-4-4. 送られた情報を表示する機能を実装

4-4-3.によりInputFormから入力された情報がAppに送られました。
次にAppからTodoListに送ります。

App.js

import './App.css';
import { useState } from 'react'
import Title from "./components/Title";
import InputForm from "./components/InputForm";
import TodoList from './components/TodoList';

function App() {

  const {todoList, setTodoList} = useState([]);

  return (
    <div>
      <Title/>
      <InputForm todoList={todoList} setTodoList={setTodoList} />
      <TodoList todoList={todoList} setTodoList={setTodoList}/>
    </div>
  );
}

export default App;

useStateの配列todoListに格納されている値をmap関数を使用して取り出していきます。
※divタグの説明コメントは削除しています。

import React from 'react';

const TodoList = ({todoList, setTodoList}) => {
  return (
    <div>
        <div>
            {todoList.map(todo => ())}
            
            <div className="todo">
                <div>
                    <span>
                        テキスト文字のテスト
                    </span>
                </div>
                <div>
                    <button>削除</button>
                </div>
            </div>
        </div>
    </div>
  )
};

export default TodoList;

そして、map関数の中に上記の黄色罫線の部分を移動させます。

import React from 'react';

const TodoList = ({todoList, setTodoList}) => {
  return (
    <div>
        <div>
            {todoList.map(todo => (
            <div className="todo">
                <div>
                    <span>テキスト文字のテスト</span>
                </div>
                <div>
                    <button>削除</button>
                </div>
            </div>
            ))}
        </div>
    </div>
  )
};

export default TodoList;

次に入力された情報をtodoとして追加できるようにしていきます。
そして、InputFormに記述したtextを指定します。

import React from 'react';

const TodoList = ({todoList, setTodoList}) => {
  return (
    <div>
        <div>
            {todoList.map(todo => (
            <div className="todo">
                <div>
                    <span>{todo.text}</span>
                </div>
                <div>
                    <button>削除</button>
                </div>
            </div>
            ))}
        </div>
    </div>
  )
};

export default TodoList;

また、一つ一つのtodoを識別するためにユニークキーを追加していきます。

import React from 'react';

const TodoList = ({todoList, setTodoList}) => {
  return (
    <div>
        <div>
            {todoList.map((todo, index) => (
            <div className="todo" key={index}>
                <div>
                    <span>{todo.text}</span>
                </div>
                <div>
                    <button>削除</button>
                </div>
            </div>
            ))}
        </div>
    </div>
  )
};

export default TodoList;

4-4-5. 追加した後の入力欄をクリアにする

typeのtextはvalueに保持されているため、inputタグ内のvalueも変更する必要があります。

import React, { useState } from 'react'

const InputForm = ({ todoList, setTodoList }) => {

  const { inputText, setInputText } = useState("");

  const hundleSubmit = (e) => {
    // 再レンダリングを停止する
    e.preventDefault();

    //タスクを追加する
    setTodoList([
      ...todoList,  //スプレット構文により、配列の中に入れていく
      {
        text: inputText
      }
    ]);

    // 追加した後の入力欄をクリアにする
    setInputText("");
  }

  const handleValue = (e) => {
    setInputText(e.target.value);
  }

  return (
    <div>
      <form onSubmit={hundleSubmit}>
        <input type="text" onChange={handleValue} value={inputText} />
        <button>
          追加
        </button>
      </form>
    </div>
  )
};

export default InputForm;

4-5. 削除ボタンを押下で、todoを削除していく機能の実装 42:30

コメント