Apps

011-Login|Step2_ReactでLogin機能を実装:コンテキストを利用したログイン状態の管理

前回の Step1 では、Reactプロジェクトのセットアップを行いました。

今回は、ReactのContext APIを利用してログイン状態を管理 し、認証情報を各コンポーネントで参照できるようにします。

1. Context APIとは?

Context API は、Reactでグローバルな状態を管理するための仕組みです。

ログイン情報のような アプリ全体で必要な状態 を管理するのに適しています。

通常、状態(state)は useState を使って管理し、親から子へ props で渡します。

しかし、ログイン状態のような情報は、複数のコンポーネントで使うため、props を渡し続けるのは非効率 です。

そこで、Context APIを使うと、どのコンポーネントからでもログイン情報を取得できるようになります。

2. LoginUserProviderの作成

まずは、ログインユーザーの情報を管理するための LoginUserProvider を作成します。

src/components/providers/LoginUserProvider.js を作成し、以下のコードを記述してください。

📌 src/components/providers/LoginUserProvider.js

import React, { createContext, useState } from 'react';

// コンテキストの作成
export const LoginUserContext = createContext({});

export const LoginUserProvider = (props) => {
    const { children } = props;

    // ログインユーザーの状態
    const [loginUser, setLoginUser] = useState("");
    const [isLogined, setIsLogined] = useState(false);

    return (
        <LoginUserContext.Provider value={{ loginUser, setLoginUser, isLogined, setIsLogined }}>
            {children}
        </LoginUserContext.Provider>
    );
};

3. コンテキストを適用

作成した LoginUserProviderApp.js でアプリ全体に適用 します。
これにより、全てのコンポーネントが LoginUserContext にアクセスできるようになります。

📌 src/App.js(修正)

import { LoginUserProvider } from './components/providers/LoginUserProvider';

function App() {
  return (
    <LoginUserProvider>  {/* 追加 */}
      <div className='App'>
        <Routes>
          <Route path='/' element={<Home />} />
          <Route path='/login' element={<Login />} />
          <Route path='/loginfailed' element={<LoginFailed />} />
          <Route path='/notfound' element={<NotFound />} />
          <Route path='/register' element={<Register />} />
        </Routes>
      </div>
      <Footer />
    </LoginUserProvider>
  );
}

export default App;

これで、LoginUserContext をアプリ全体で利用できるようになりました。

4. useContext を用いた状態管理

次に、コンテキストを使ってログイン状態を管理 できるようにします。

📌 src/components/hooks/useLogin.js

import React, { useContext } from 'react';
import { useNavigate } from 'react-router-dom';
import axios from 'axios';
import { LoginUserContext } from "../providers/LoginUserProvider";

export const useLogin = () => {
    const { setLoginUser, setIsLogined } = useContext(LoginUserContext);
    const navigate = useNavigate();

    const login = (user) => {
        console.log("ログイン処理開始");
        console.log("入力されたユーザー名:", user.username);

        const endpoint = "https://jsonplaceholder.typicode.com/users";

        axios.get(endpoint)
            .then((res) => {
                // レスポンスのデータを取得し、ユーザーを探す
                const foundUser = res.data.find(u => 
                    u.username === user.username && String(u.id) === user.password
                );

                if (foundUser) {
                    console.log("ログイン成功:", foundUser);
                    setLoginUser(foundUser.username);  // ログインユーザーをセット
                    setIsLogined(true);  // ログイン状態をtrueに
                    navigate("/", { state: { username: foundUser.username } });
                } else {
                    console.log("ユーザーが見つかりません");
                    navigate("/loginfailed");
                }
            })
            .catch(error => {
                console.error("ログインエラー:", error);
            });
    };

    return { login };
};

🔹 useLogin.js のポイント

  • useContext(LoginUserContext) を使い、setLoginUsersetIsLogined を取得
  • APIから取得したユーザー情報と入力情報を照合
  • ログイン成功時に ログインユーザー名をグローバル状態に保存 し、isLoginedtrue に設定
  • navigate() を用いて画面遷移

5. ログイン情報の表示

ヘッダーに 現在ログインしているユーザーの名前 を表示します。

📌 src/components/templates/Header.js

import React, { useContext } from 'react';
import { AppBar, Toolbar, Typography, Button, Box } from '@mui/material';
import BasicMenu from '../elements/BasicMenu';
import Grid from '@mui/material/Grid';
import { LoginUserContext } from '../providers/LoginUserProvider';

const Header = () => {
  const { loginUser, isLogined } = useContext(LoginUserContext);

  return (
    <AppBar position="static">
      <Toolbar>
        <Box sx={{ flexGrow: 1 }}>
          <Grid container spacing={2}>
            <Grid item>
              <BasicMenu />
            </Grid>
            <Grid item xs={10} sx={{ py: 1 }}>
              <Typography variant="p">
                {isLogined ? `ログインユーザー:${loginUser}` : "ログインしていません"}
              </Typography>
            </Grid>
            <Grid item>
              <Button color="inherit">Login</Button>
            </Grid>
          </Grid>
        </Box>
      </Toolbar>
    </AppBar>
  );
};

export default Header;

🔹 Header.js のポイント

  • useContext(LoginUserContext)loginUserisLogined を取得
  • isLoginedtrue のときは「ログインユーザー名」を表示し、false のときは「ログインしていません」と表示

6. ログイン状態によるリダイレクト

ログインしていない場合、Home.js でログインページにリダイレクトするように設定します。

📌 src/components/pages/Home.js

import React, { useContext } from 'react';
import Header from '../templates/Header';
import { Navigate, useLocation } from 'react-router-dom';
import { LoginUserContext } from '../providers/LoginUserProvider';

const Home = () => {
  const { isLogined } = useContext(LoginUserContext);
  const location = useLocation();
  const username = location.state?.username || "ゲスト";

  if (!isLogined) {
    return <Navigate to="/login" />;
  } else {
    return (
      <>
        <Header />
        <h1>Home</h1>
        <p>ようこそ、{username} さん!</p>
      </>
    );
  }
};

export default Home;

🔹 Home.js のポイント

  • isLoginedfalse の場合、Navigate を使って /login にリダイレクト
  • ログイン成功時に Home に遷移し、ユーザー名を表示

まとめ

LoginUserProvider を作成し、グローバルなログイン情報を管理
useContext を使って、各コンポーネントでログイン情報を参照
isLogined を使い、未ログイン時は /login にリダイレクト
Header でログインユーザー名を表示

次のステップでは、ログアウト機能の実装 を行います! 🚀

-Apps