0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

入力内容をInputタグからフォーカスを外した時に保存する

Posted at

はじめに

Inputフィールドに入力した後、「保存ボタン」や「送信ボタン」を押すことなく、内容保存できる機能の作成となると複数方法があると思います。

  1. Qiitaのように、記事の内容を1文字追加・削除する度にPOST Requestをサーバーサイドに投げる
  2. 入力が始まって、何秒か経過したらPOST Requestをサーバーサイドに投げる
  3. Inputフィールド以外の何かをクリックしたらPOST Requestをサーバーサイドに投げる
  4. 入力内容をInputタグからフォーカスを外した時に保存する

まだあるかもしれませんが、今回は4番目の内容についてまとめます。
テストで使用するメソッドはこちらです。

await fireEvent.blur(getByLabelText('username'))

Testing Library 公式Doc

完成図

GIF Maker video to GIF.gif

  1. 「Blur Sample」のタイトルが
  2. inputフィールド
  3. 「Memo Record」のサブタイトル
  4. DBから引っ張ってきた文字の表示

全体構成

Backend側の実装も行なっています。
本筋と異なるので記載はしませんが、下記画像のような構成になっています。

image.png

テスト & 実装

TDDの勉強も兼ねて、テストと実装を書いたので内容は省略しますが、細かくテストを書いていきました。

Screen層の役割は、Repository層のpostMemoメソッドに正しい引数を渡すことです。
Test DoubleのSpyを使用してテスト用のRepositoryを作成します。

SpyRepository.ts
import { UserRepository } from "../../repository/UserRepository.ts";
import { UserMemo } from "../../type/TypeMemoRepository.ts";

export class SpyUserRepository implements UserRepository {
    postMemo_argumentValue:UserMemo | null = null
    
    postMemo(inputObject: UserMemo): void {
        this.postMemo_argumentValue = inputObject
    }
    async getAllMemo(): Promise<UserMemo[]> {
        // ...省略
    }

}

次にScreen層(App.tsx)のテストです。

App.test.tsx
import {describe, expect, test} from "vitest"
import { screen, render, fireEvent } from "@testing-library/react"
import App from "../App.tsx";
import { MemoScreen } from "../screens/MemoScreen.tsx";
import { SpyUserRepository } from "./repository/SpyUserRepository.ts";
import { userEvent } from "@testing-library/user-event";

describe("Appのテスト", () => {
        test('Appをレンダリングした時に「Blur Sample」の文字が見える', () => {
            // ...省略
        })

        test('Appをレンダリングした時に、inputフィールドがある', () => {
            // ...省略
        })

        test('Appをレンダリングした時に、MemoScreenコンポーネントをレンダリングする', () => {
            // ...省略
        })

        test('メモを入力し、フォーカスを外した時にuserRepositoryのpostMemoメソッドを正しい引数で呼んでいる', async() => {
               const spyUserRepository = new SpyUserRepository()
                render(<App userRepository={spyUserRepository}/>)
                const inputField = screen.getByRole('textbox')
                await userEvent.type(inputField, 'Test Memo')

                await fireEvent.blur(inputField)

                expect(spyUserRepository.postMemo_argumentValue?.memo).toEqual('Test Memo')
        })
})

そして、実装です。

App.tsx
import './App.css'
import { MemoScreen } from './screens/MemoScreen'
import { DefaultUserRepository, UserRepository } from "./repository/UserRepository.ts";
import { useEffect, useRef, useState } from "react";
import { UserMemo } from "./type/TypeMemoRepository.ts";

type Props = {
    userRepository?: UserRepository
}

function App({ userRepository = new DefaultUserRepository() }: Props) {
    const inputRef = useRef<HTMLInputElement>(null)
    const [memo, setMemo] = useState<UserMemo[]>([])
    const postMemo = async () => {
        if (inputRef.current) {
            const inputObject = {
                memo : inputRef.current.value
            }
            await userRepository.postMemo(inputObject)
            inputRef.current.value = ''
        }
    }

    useEffect(() => {
        const getAllMemo = async () => {
            const res = await userRepository.getAllMemo()
            setMemo(res)
        }
        getAllMemo()
    }, [memo])

    return (
        <>
            <h1>Blur Sample</h1>
            <input
                ref={inputRef}
                onBlur={postMemo}
            />
            <MemoScreen memo={memo}/>
        </>
    )
}

export default App

テスト側:await fireEvent.blur(<対象のelement>)
実装側:<input onBlur={<保存処理>} />

完成図のように、inputフィールドからフォーカスを外した時に、保存ができるようになりました。

最後に

すごく簡単はフルスタックアプリでしたが、学びが多かったです!
もっと作っていくことで、基本的なことを頭に叩き込んでいこうと思います!!

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?