【無料配布】10日間で学べるTypeScript学習資料

【TypeScript】フロントエンド開発におけるReactを利用したToDoアプリ開発

本記事では、以下の構成フォルダにてTypeScriptによるToDoアプリ開発を解説します。

todo-app
├─public
│ ├─index.html
│ └─(Create React Appの場合にその他ファイル)
├─src
│ ├─componets
│ │ └─App.tsx
│ └─index.tsx
└─package.json等
目次

TypeScriptとJavaScriptの違い

TypeScriptは、”JavaScript + 静的型付け”である言語です。

つまり、端的にTypeScriptとJavaScriptの違いで言えば、静的型付けが利用できるかどうかになります。

TypeScriptとJavaScriptがどのような関係にあるか理解することで、TypeScriptの学習の上で重要になります。

そのため、JavaScriptよりも覚えることが多く、比較すると難易度が高めになります。

TypeScriptにおけるアプリケーション開発

TypeScriptを学習したのち最終的にはアプリケーション開発に着手します。

また、代表的なTypeScriptの開発領域は以下になります。

上記のように、逆算してどの開発領域でアプリケーション開発をするかゴール設定しておかなければスムーズな着手に移行できません。

ただし、いきなり開発領域を見せられて何をするべきか迷っても仕方ありません。

そのため、自身でサンプルアプリあるいはチュートリアルアプリとして選ぶなら以下の開発領域一択かなと考えます。

TypeScript × フロントエンド開発

まずは簡易的なアプリとしてToDoアプリ開発などがおすすめです。

ToDoアプリ開発からの着手をおすすめする理由は以下になります。

スクロールできます
おすすめ内容理由
機能がシンプルで学習のハードルが低い「追加・表示・編集・削除」といった基本的な操作に絞られている。
TypeScriptやReact/Vueなどフロント技術の学習対象をシンプルに体験できる。
状態管理を自然に学べるタスクの「追加」「完了済みへの変更」「削除」などは状態管理の典型例である。
フロント開発で必須となる状態管理の概念(useState/useReducer/Zustand/Reduxなど)を実際の動作を通して学べる。
型定義の重要性を実感できるToDoデータは「id」「タイトル」「完了フラグ」などのプロパティを持つ。
型を定義すると関数間のデータ受け渡しが明確になり、ミスが防げることを体感できる。
UIコンポーネント分割の練習になる小さなアプリの中で「コンポーネント設計」の基本が練習できる点はフロント開発の学習に最適である。
イベント処理と双方向データバインディングを学べる入力欄に文字を打つ、ボタンをクリックする、チェックボックスを切り替えるなどのユーザーイベントを扱う練習ができる。
フロント開発の本質的な要素であり、ToDoアプリで繰り返し登場するため学習効果が高い。
ローカルストレージやAPI接続など拡張しやすい初期段階では「ブラウザ上だけのToDoアプリ」を作り、その後「ローカルストレージに保存」「バックエンドAPIと連携」などに拡張可能。
完成のイメージがつきやすく達成感がある完成形を想像しやすいのでモチベーションを保ちやすい。
短期間で「動くもの」を作れるため、学習の初期段階での達成感を得やすい。
なぜToDoアプリから始めるのがおすすめか

まとめると、ToDoアプリは「小規模だがフロント開発の本質(状態管理/型定義/イベント処理/UI設計)を自然に学べる教材」だからこそ、TypeScript学習の第一歩に最適と考えます。

TypeScript等の開発環境構築

TypeScriptによるアプリ開発を実施するためには、プログラミング言語に限らず開発環境構築が必要です。

TypeScriptを利用するためには、以下の開発環境を整える必要があります。

TypeScriptの開発環境構築
  • Node.jsのインストール
  • TypeScriptのインストール
  • VSCodeのインストール

TypeScriptを利用するために、Node.jsのインストールが必要になります。

基本的に、最新版をインストールすれば問題ありません。

各種必要なインストーラーの実施方法を詳しく知りたい人は、「【TypeScript】インストール方法や開発環境構築を徹底解説!」を一読ください。

TypeScriptとReactにおけるプロジェクト作成

必要なプログラミング言語・ソフトウェアをインストールできた段階で、アプリ開発時のプロジェクトを作成します。

cd [任意のディレクトリ名]
mkdir [任意のディレクトリ作成]
cd [作成したディレクトに移動]

あなたが利用したい任意のディレクトリまで移動し、プロジェクトフォルダを作成してください。

作成後、作成したディレクトリに移動します。

TypeScriptとReactを利用したToDoアプリ開発

あくまでフロントエンド開発の一つのチュートリアルとして参考ください。(サーバーサイドは触れない)

ここでは、TypeScriptとReactフレームワークを利用して簡易的なToDoアプリを開発していきます。

npx create-react-app [任意のプロジェクト名] --template typescript

上記のコマンドを任意のディレクトリで実行すると、TypeScriptとReactの新規プロジェクトが作成されます。

また、初期配置のプロジェクトファイルは主に以下の構成で進めていきます。

todo-app
├─public
│ ├─index.html
│ └─(Create React Appの場合にその他ファイル)
├─src
│ ├─componets
│ │ └─App.tsx
│ └─index.tsx
└─package.json等

上記を踏まえた上で、各ファイルのコーディングについて解説します。

また、事前準備として、index.tsxに以下を記述します。

import { render } from "react-dom";
import { App } from "./components/App";

const rootElement = document.getElementById("root");
render(<App />, rootElement);

モジュール間でデータを受け渡す方法としてimport宣言とexport宣言がありますが、ここではimport宣言によって各モジュールからデータを受け取っています。

また、変数rootElementを定義し、Appオブジェクトをレンダリングしています。

App.tsxにおける実装

ここでは、まず全ての処理をApp.tsxに記述している例になります。

import { ChangeEvent, useState, FC } from "react";
import styled from "styled-components";

export const App: FC = () => {
  //テキストボックスStateの記述
  const [text, setText] = useState<string>("");
  //メモ一覧Stateの記述
  const [memos, setMemos] = useState<string[]>([]);

  //テキストボックス入力時に入力内容をStateに設定
  const onChangeText = (e: ChangeEvent<HTMLInputElement>) => setText(e.target.value);

  //[追加]ボタン押下時
  const onClickAdd = () => {
    //State変更を正常に検知させるために新たな配列を生成
    const newMemos = [...memos];
    //テキストボックスの入力内容をメモ配列に追加
    newMemos.push(text);
    setMemos(newMemos);
    //テキストボックスを空にする
    setText("");
  };

  //[削除]ボタン押下時(何番目が押されたか引数で受け取る)
  const onClickDelete = (index: number) => {
    //State変更を正常に検知させるため新たな配列を生成
    const newMemos = [...memos];
    //メモ配列から該当の要素を削除
    newMemos.splice(index, 1);
    setMemos(newMemos);
  };

  return (
    <div>
      <h1>ToDo App</h1>
      <input type="text" value={text} onChange={onChangeText} />
      <SButton onClick={onClickAdd}>Add</SButton>
      <SContainer>
        <p>Memos</p>
        <ul>
          {memos.map((memo, index) => (
            <li key={memo}>
              <SMemoWrapper>
                <p>{memo}</p>
                <SButton onClick={() => onClickDelete(index)}>Delete</SButton>
              </SMemoWrapper>
            </li>
          ))}
        </ul>
      </SContainer>
    </div>
  );
};

const SButton = styled.button`
  margin-left: 16px;
`;

const SContainer = styled.div`
  border: solid 1px #ccc;
  padding: 16px;
  margin: 8px;
`;

const SMemoWrapper = styled.div`
  display: flex;
  align-items: center;
`;

import文では、各種必要なモジュールからデータを受け取っています。

また、CSSライブラリは何を利用してもよいですが、本プログラムではstyled-componentsを利用しています。

export文ではAppに関する処理を実装しています。

最後に、ボタン等の定義を実装しています。

コンポーネント化における実装

フロントエンド開発では、コンポーネント化といった概念も理解しておく必要があります。

ここでは、メモ一覧を表示させるエリアをコンポーネント化できるので、例として以下のコードを作成します。

その際のフォルダ構成を一部追加します。

todo-app
├─public
│ ├─index.html
│ └─(Create React Appの場合にその他ファイル)
├─src
│ ├─componets
│ │ ├─App.tsx
│ │ └─MemoList.tsx(ファイル追加)
│ └─index.tsx
└─package.json等

作成したMemoList.tsxに対してApp.tsxの一部画面要素を移植していきます。

import { FC } from "react";
import styled from "styled-components";

//必要なPropsはメモ一覧と削除時に実行する関数
type Props = {
    memos: string[];
    onClickDelete: (index: number) => void;
};

export const MemoList: FC<Props> = props => {
    const { memos, onClickDelete } = props;

    return (
        <SContainer>
        <p>Memos</p>
        <ul>
          {memos.map((memo, index) => (
            <li key={memo}>
              <SMemoWrapper>
                <p>{memo}</p>
                <SButton onClick={() => onClickDelete(index)}>Delete</SButton>
              </SMemoWrapper>
            </li>
          ))}
        </ul>
      </SContainer>
    );
};

const SButton = styled.button`
  margin-left: 16px;
`;

const SContainer = styled.div`
  border: solid 1px #ccc;
  padding: 16px;
  margin: 8px;
`;

const SMemoWrapper = styled.div`
  display: flex;
  align-items: center;
`;

MemoList.tsxにて、メモ一覧部分をコンポーネント化に成功しました。

また、一部画面要素を移植できたので、App.tsxの修正が必要になります。

import { ChangeEvent, useState, FC, useCallback } from "react";
import styled from "styled-components";
import { MemoList } from "./MemoList";

export const App: FC = () => {
  //テキストボックスStateの記述
  const [text, setText] = useState<string>("");
  //メモ一覧Stateの記述
  const [memos, setMemos] = useState<string[]>([]);

  //テキストボックス入力時に入力内容をStateに設定
  const onChangeText = (e: ChangeEvent<HTMLInputElement>) => setText(e.target.value);

  //[追加]ボタン押下時
  const onClickAdd = () => {
    //State変更を正常に検知させるために新たな配列を生成
    const newMemos = [...memos];
    //テキストボックスの入力内容をメモ配列に追加
    newMemos.push(text);
    setMemos(newMemos);
    //テキストボックスを空にする
    setText("");
  };

  //[削除]ボタン押下時(何番目が押されたか引数で受け取る)
  const onClickDelete = useCallback((index: number) => {
    //State変更を正常に検知させるため新たな配列を生成
    const newMemos = [...memos];
    //メモ配列から該当の要素を削除
    newMemos.splice(index, 1);
    setMemos(newMemos);
  }, [memos]);

  return (
    <div>
      <h1>ToDo App</h1>
      <input type="text" value={text} onChange={onChangeText} />
      <SButton onClick={onClickAdd}>Add</SButton>
      <MemoList memos={memos} onClickDelete={onClickDelete} />
    </div>
  );
};

const SButton = styled.button`
  margin-left: 16px;
`;

ファイル変更前と比較して、コンポーネント化した部分をApp.tsxから追加・削除したことが分かります。

このようにコンポーネント化によって得られるメリットがいくつか存在します。

コンポーネント化によるメリット
  • 画面の各要素をコンポーネント化し使いまわせる
  • コンポーネント一つを修正することで全体に変更が適用される

カスタムフック化における実装

最後に、ToDoに関するロジックとメモ一覧データをカスタムフックによって分離してみましょう。

hooksフォルダを作成し、配下にuseMemoList.tsをカスタムフックとして作成し実装します。

todo-app
├─public
│ ├─index.html
│ └─(Create React Appの場合にその他ファイル)
├─src
│ ├─componets
│ │ ├─App.tsx
│ │ └─MemoList.tsx
│ ├─hooks(フォルダ追加)
│ │ └─useMemoList.ts(ファイル追加)
│ └─index.tsx
└─package.json等

hooksフォルダとuseMemoList.tsを追加しています。

先に、useMemoList.tsから実装していきます。

import { useCallback, useState } from "react";

//メモ一覧に関するカスタムフック
export const useMemoList = () => {
    //メモ一覧State
    const [memos, setMemos] = useState<string[]>([]);
    
    //メモ追加ロジック
    const addTodo = useCallback((text: string) => {
        //State変更を正常に検知させるために新たな配列を生成
        const newMemos = [...memos];
        //テキストボックスの入力内容をメモ配列に追加
        newMemos.push(text);
        setMemos(newMemos);
        //依存配列に忘れずにmemosを設定
    }, [memos]);

    //メモ削除ロジック
    const deleteTodo = useCallback((index: number) => {
        //State変更を正常に検知させるため新たな配列を生成
        const newMemos = [...memos];
        //メモ配列から該当の要素を削除
        newMemos.splice(index, 1);
        setMemos(newMemos);
    }, [memos]);

    return { memos, addTodo, deleteTodo };
};

作成した各関数(addTodoとdeleteTodo)がそれぞれ追加ロジックと削除ロジックを担います。

このようにロジックを分離することで他のコンポーネントでも使いまわすことができます。

また、一部機能を移植できたので、App.tsxの修正が必要になります。

import { ChangeEvent, useState, FC, useCallback } from "react";
import styled from "styled-components";
import { MemoList } from "./MemoList";
import { useMemoList } from "../hooks/useMemoList";

export const App: FC = () => {
  //カスタムフックからそれぞれ取得
  const { memos, addTodo, deleteTodo } = useMemoList();
  //テキストボックスStateの記述
  const [text, setText] = useState<string>("");

  //テキストボックス入力時に入力内容をStateに設定
  const onChangeText = (e: ChangeEvent<HTMLInputElement>) => setText(e.target.value);

  //[追加]ボタン押下時
  const onClickAdd = () => {
    //カスタムフックのメモ追加ロジック実行
    addTodo(text);
    //テキストボックスを空にする
    setText("");
  };

  //[削除]ボタン押下時(何番目が押されたか引数で受け取る)
  const onClickDelete = useCallback((index: number) => {
    //カスタムフックのメモ削除ロジック実行
    deleteTodo(index); 
  }, [deleteTodo]);

  return (
    <div>
      <h1>ToDo App</h1>
      <input type="text" value={text} onChange={onChangeText} />
      <SButton onClick={onClickAdd}>Add</SButton>
      <MemoList memos={memos} onClickDelete={onClickDelete} />
    </div>
  );
};

const SButton = styled.button`
  margin-left: 16px;
`;

ファイル変更前に比べると、カスタムフック化した部分をApp.tsxから追加・削除したことが分かります。

このようにカスタムフック化によって得られるメリットがいくつか存在します。

カスタムフック化によるメリット
  • ロジックをコンポーネントから分離できる
  • 複数コンポーネントにロジックを再利用できる

コンポーネント化とカスタムフック化を理解することで、フロントエンドにおけるアプリ開発時の効率アップにつながります。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

CAPTCHA


目次