Closed3

Error: ( ) is not a function というエラーに遭遇

さとよしさとよし

useLogin.tsx

"use client"
import useApi from "@/hooks/useApi"
import { useCallback, useEffect, useState } from "react"

interface UseLoginReturnType {
    data: any
    error: any
    loading: boolean
    email: string
    password: string
    setEmail: React.Dispatch<React.SetStateAction<string>>
    setPassword: React.Dispatch<React.SetStateAction<string>>
    fetchLoginData: () => void
    handleLogin: (e: React.FormEvent<HTMLFormElement>) => void
}

const useLogin = (): UseLoginReturnType => {
    const [email, setEmail] = useState<string>("")
    const [password, setPassword] = useState<string>("")
    const { data, error, loading, refetch } = useApi()

    const fetchLoginData = useCallback(() => {
        refetch("/auth/login", {
            method: "POST",
            data: { email, password }
        })
    }, [refetch])

    const handleLogin = useCallback(async (e: React.FormEvent<HTMLFormElement>) => {
        e.preventDefault()
        await fetchLoginData()
    }, [fetchLoginData])

    useEffect(() => {
        if (data) {
            console.log(data)
        }
    }, [data])

    return {
        data,
        error,
        loading,
        fetchLoginData,
        handleLogin,
        email,
        password,
        setEmail,
        setPassword
    }
}

export default useLogin

auth/login/page.tsx

import React from 'react'
import Link from 'next/link'
import { InputField, Button } from '@/components'
import { FaSignInAlt } from 'react-icons/fa'
import { useLogin } from '@/features/auth'

const LoginPage = () => {

    const {
        data,
        error,
        loading,
        email,
        password,
        setEmail,
        setPassword,
        handleLogin
    } = useLogin()

    return (
        <div className="min-h-screen flex items-center justify-center bg-base02">
            <div className="bg-white p-8 rounded-lg shadow-lg w-full max-w-md">
                <h1 className="text-3xl font-bold text-main01 mb-6 text-center">ログイン</h1>
                <form className="space-y-4" onSubmit={handleLogin}>
                    <InputField
                        type="email"
                        id="email"
                        placeholder="your@email.com"
                        label="メールアドレス"
                        value={email}
                        onChange={(e) => setEmail(e.target.value)}
                    />
                    <InputField
                        type="password"
                        id="password"
                        placeholder="••••••••"
                        label="パスワード"
                        value={password}
                        onChange={(e) => setPassword(e.target.value)}
                    />
                    <Button
                        type="submit"
                        text="ログイン"
                        icon={<FaSignInAlt className="inline-block mr-2" />}
                        loading={loading}
                    />
                </form>
                <div className="mt-4 text-center">
                    <Link href="/auth/register" className="text-accent02 hover:underline">
                        アカウントをお持ちでない方はこちら
                    </Link>
                </div>
            </div>
        </div>
    )
}

export default LoginPage

さとよしさとよし

"use client"ディレクティブを追加することでエラーが解決。

  1. Next.jsのApp Routerでは、デフォルトでサーバーコンポーネントが使用されます。サーバーコンポーネントはサーバー側でレンダリングされ、クライアント側のJavaScriptを最小限に抑える。
  2. しかし、useLoginフックはクライアントサイドの機能(状態管理、イベントハンドリングなど)を使用しています。これらの機能はサーバー側では利用できない。
  3. "use client"ディレクティブを追加することで、Next.jsにこのコンポーネントとその子コンポーネントをクライアントサイドでレンダリングするよう指示。これにより、useLoginフックやその他のクライアントサイド機能が正常に動作するようになる。
  4. 特に、useLoginフックの実装を見ると、以下の部分でクライアントサイドの機能を使用している。
"use client"
import useApi from "@/hooks/useApi"
import { useCallback, useEffect, useState } from "react"

interface UseLoginReturnType {
    data: any
    error: any
    loading: boolean
    email: string
    password: string
    setEmail: (email: string) => void;
    setPassword: (password: string) => void;
    fetchLoginData: () => void
    handleLogin: (e: React.FormEvent<HTMLFormElement>) => void
}

const useLogin = (): UseLoginReturnType => {
    const [email, setEmail] = useState<string>("")
    const [password, setPassword] = useState<string>("")
    const { data, error, loading, refetch } = useApi()
  1. これらの機能(useState, useCallback, useEffect)はクライアントサイドでのみ動作するため、"use client"ディレクティブが必要である。
  2. また、フォームの送信やユーザーインタラクションを処理するために、このコンポーネントはクライアントサイドで動作する必要がある。
  3. 結論として、"use client"ディレクティブを追加することで、LoginPageコンポーネントとその中で使用されているフックやイベントハンドラーがクライアントサイドで正しく動作するようになり、エラーが解決される。
このスクラップは2ヶ月前にクローズされました