【初心者が実践】React&TypeScriptでメモアプリ作成してみた

スポンサーリンク
JavaScript

参考書籍

こちらの書籍のメモアプリ作成を完全に参考にしました。わかりやすい情報ありがとうございます。

モダンJavaScriptの基本から始める React実践の教科書 (最新ReactHooks対応) | じゃけぇ(岡田 拓巳) | コンピュータ・IT | Kindleストア | Amazon
Amazonでじゃけぇ(岡田 拓巳)のモダンJavaScriptの基本から始める React実践の教科書 (最新ReactHooks対応)。アマゾンならポイント還元本が多数。一度購入いただいた電子書籍は、KindleおよびFire端末、スマートフォンやタブレットなど、様々な端末でもお楽しみいただけます。

事前準備

①ターミナルを起動し、任意のフォルダで以下コマンドを実行
npx create-react-app memoapp –template typescript

②以下コマンド実行でローカル環境を立ち上げる
cd memoapp
npm start

③以下URLにアクセス
http://localhost:3000/

以下のような画面が表示されればOK

④プロジェクト(memoapp)の階層は以下のようにしておく
(create-react-appによるプロジェクト作成で余計なフォルダも作成されていますが赤字ファイルが存在していれば良い認識)

memoapp
│
├── package-lock.json
├── package.json
├── public
│   ├── favicon.ico
│   ├── index.html
│   ├── logo192.png
│   ├── logo512.png
│   ├── manifest.json
│   └── robots.txt
├── src
│   ├── App.css
│   ├── components
│   │   └── App.tsx
│   ├── index.css
│   ├── index.tsx
│   ├── logo.svg
│   ├── react-app-env.d.ts
│   ├── reportWebVitals.ts
│   └── setupTests.ts
└── tsconfig.json

⑤index.tsxとApp.tsxファイル中身を以下に変更しておく

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

const rootElement = document.getElementById('root');

render(
    <App />,
  rootElement
);
import '../App.css';

export const App =() =>{
  return <h1>メモアプリ</h1>
};

画面表示はこんな感じ

⑥CSSはスタイルコンポーネントにて実装するため、以下コマンドでinstallも済ませておく

npm install styled-components
npm install @types/styled-components

ここから実際に書いていく

書籍では3パターンの書き方が記載あったのでそれぞれ順番に実装してみました。

①全ての処理を1ファイルに記述する方法

App.tsxに全ての処理を記載する方法で実装してみました。
コードは以下。

//App.cssのスタイルを効かせる(全体用)
import '../App.css';
//各種必要機能のimport
import {useState,FC, ChangeEvent} from 'react';
//スタイルコンポーネントのimport
import styled from 'styled-components';

export const App = () => {

//Stateの定義
//テキストボックスの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更新のため、memos要素を代入した配列を生成
  const newMemos = [...memos];
  // 入力した内容を追加する
  newMemos.push(text);
  //newMemosの内容をmemosにセットし、Stateの変数内容を変更する
  setMemos(newMemos);
  //テキストボックスを空にする
  setText('');
};

//削除ボタン押下時の処理を設定
const onClickDelete = (index:number) => {
  //State更新のため、memos要素を代入した配列を生成
  const newMemos = [...memos];
  //対象のメモ内容を取り除く
  newMemos.splice(index,1);
  //newMemosの内容をmemosにセットし、Stateの変数内容を変更する
  setMemos(newMemos);
};


  return (<div>
    <h1>メモアプリ</h1>
    <input type='text' value={text} onChange={onChangeText} placeholder='メモを入力'/>
    <SButton onClick={onClickAdd}>追加</SButton>
    <p>メモ一覧</p>
    <SContainer>
      <ul>
        {memos.map((memo,index)=>(
          <li key={memo}>
            <SMemoWrapper>
              <p>{memo}</p>
            </SMemoWrapper>
            <SButton onClick={() => onClickDelete(index)}>削除</SButton>
          </li>
        ))}
      </ul>
    </SContainer>
    </div>
  );
};

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

const SContainer = styled.div`
  padding: 0.5em 1em;
  margin: 2em 0;
  color: #5d627b;
  background: white;
  border-top: solid 5px #5d627b;
  box-shadow: 0 3px 5px rgba(0, 0, 0, 0.22);
`;

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

画面はこんな感じ。

②コンポーネント化した実装

次は①の実装をベースに、メモ一覧部分はコンポーネント化してみます。
具体的には、components配下にMemoList .tsxファイルを作成して、メモ一覧部分の記述を移植していきます。
コードは以下。

//App.cssのスタイルを効かせる(全体用)
import '../App.css';
//各種必要機能のimport
import {useState,FC, ChangeEvent} from 'react';
//スタイルコンポーネントのimport
import styled from 'styled-components';
//子コンポーネントのimport
import {MemoList} from './MemoList';
import { useCallback } from 'react';

export const App:FC = () => {

//Stateの定義
//テキストボックスの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更新のため、memos要素を代入した配列を生成
  const newMemos = [...memos];
  // 入力した内容を追加する
  newMemos.push(text);
  //newMemosの内容をmemosにセットし、Stateの変数内容を変更する
  setMemos(newMemos);
  //テキストボックスを空にする
  setText('');
};

//削除ボタン押下時の処理を設定
const onClickDelete = useCallback((index:number) => {
  //State更新のため、memos要素を代入した配列を生成
  const newMemos = [...memos];
  //対象のメモ内容を取り除く
  newMemos.splice(index,1);
  //newMemosの内容をmemosにセットし、Stateの変数内容を変更する
  setMemos(newMemos);
},[memos]);


  return (<div>
    <h1>メモアプリ</h1>
    <input type='text' value={text} onChange={onChangeText} placeholder='メモを入力'/>
    <SButton onClick={onClickAdd}>追加</SButton>
    <p>メモ一覧</p>
    <MemoList memos={memos} onClickDelete={onClickDelete}></MemoList>
    </div>
  );
};

const SButton = styled.button`
  margin-left:16px;
`;
//各種必要機能のimport
import {FC} from 'react';
//スタイルコンポーネントのimport
import styled from 'styled-components';


type Props = {
    memos:string[];
    onClickDelete:(index:number) => void;
}

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

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

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

const SContainer = styled.div`
  padding: 0.5em 1em;
  margin: 2em 0;
  color: #5d627b;
  background: white;
  border-top: solid 5px #5d627b;
  box-shadow: 0 3px 5px rgba(0, 0, 0, 0.22);
`;

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

これで画面は①と変わらず、メモ一覧部分をコンポーネント化することができました。

③カスタムフック化

メモに関するロジックと一覧データを分離してカスタムフック化を行いま。
具体的にはhooksフォルダを作成して、その配下にuseMemoList.tsを作成します。

コードは以下。

//App.cssのスタイルを効かせる(全体用)
import '../App.css';
//各種必要機能のimport
import {useState,FC, ChangeEvent} from 'react';
//スタイルコンポーネントのimport
import styled from 'styled-components';
//子コンポーネントのimport
import {MemoList} from './MemoList';
//カスタムフックのためのMemoList.tsのimport
import {useMemoList} from '../hooks/useMemoList';
//useCallbackのimport
import { useCallback } from 'react';

export const App:FC = () => {

//カスタムフックから取得するものを設定
const {memos,addTodo,deleteTodo} = useMemoList();
//Stateの定義
//テキストボックスの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>メモアプリ</h1>
    <input type='text' value={text} onChange={onChangeText} placeholder='メモを入力'/>
    <SButton onClick={onClickAdd}>追加</SButton>
    <p>メモ一覧</p>
    <MemoList memos={memos} onClickDelete={onClickDelete}></MemoList>
    </div>
  );
};

const SButton = styled.button`
  margin-left:16px;
`;
//各種必要機能のimport
import {FC} from 'react';
//スタイルコンポーネントのimport
import styled from 'styled-components';


type Props = {
    memos:string[];
    onClickDelete:(index:number) => void;
}

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

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

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

const SContainer = styled.div`
  padding: 0.5em 1em;
  margin: 2em 0;
  color: #5d627b;
  background: white;
  border-top: solid 5px #5d627b;
  box-shadow: 0 3px 5px rgba(0, 0, 0, 0.22);
`;

const SMemoWrapper = styled.div`
  display:flex;
  align-items:center;
`;
//useCallbackのimport
import { useCallback,useState } from "react";


export const useMemoList = () => {

    //メモ一覧のStateを定義
    const [memos,setMemos] = useState<string[]>([]);

    //メモ追加ロジック
    const addTodo = useCallback((text:string) => {
        //State更新のため、memos要素を代入した配列を生成
        const newMemos = [...memos];
        // 入力した内容を追加する
        newMemos.push(text);
        //newMemosの内容をmemosにセットし、Stateの変数内容を変更する
        setMemos(newMemos);
    },[memos]);

    //メモ削除ロジック
    const deleteTodo =useCallback((index:number) => {
        //State更新のため、memos要素を代入した配列を生成
        const newMemos = [...memos];
        //対象のメモ内容を取り除く
        newMemos.splice(index,1);
        //newMemosの内容をmemosにセットし、Stateの変数内容を変更する
        setMemos(newMemos);
    },[memos]);

    return {memos,addTodo,deleteTodo}
};

画面は①と変わらず、メモロジックをコンポーネント化することができました。

終わりに

削除機能で使用するspliceは初見だったので↓から確認しました。

JavaScriptのspliceメソッドについて現役エンジニアが解説【初心者向け】
https://techacademy.jp/magazine/37922

読んでいただきありがとうございました!

コメント

タイトルとURLをコピーしました