学生向けプログラミング入門 | 無料

学生向けにプログラミングを無料で解説。Java、C++、Ruby、PHP、データベース、Ruby on Rails, Python, Django

Django3.2 | 13 | QRオーダーシステムの構築 | ユーザー登録

[12 | Auth Context] << [ホーム] >> [14 | 飲食店登録実装]

「qrmenu_react/src/apis.js」ファイルを編集します。


記述編集 【QRMenu/qrmenu_react/src/apis.js】

import { toast } from 'react-toastify';

function request(path,  {data = null, token = null, method = "GET" }) {
  return fetch(path, {
    method,
    headers: {
      Authorization: token ? `Token ${token}` : "",
      "Content-Type": "application/json",
    },
    body: method !=="GET" && method !== "DELETE" ? JSON.stringify(data): null,
  })
    .then((response) => {

      //もし成功したら
      if (response.ok) {
        if(method === "DELETE") {
          return true;
        }
        toast.success("ログイン成功");
        return response.json();
      }
      //失敗
      return response.json().then((json) => {
          //JSONエラー
          if (response.status === 400) {
            toast.error("氏名もしくはパスワードに間違いがあります。");
            const errors = Object.keys(json).map(
                (k) => `${(json[k].join(" "))}`
            );
            throw new Error(errors.join(" "));
          }
          throw new Error(JSON.stringify(json));
        })
        .catch((e) => {
          if (e.name === "SyntaxError") {
            throw new Error(response.statusText);
          }
          throw new Error(e);
        })
    })

    .catch((e) => {
      //全エラー
      toast(e.message, { type: "error" });
    })
}

export function signIn(username, password) {
  return request("/auth/token/login/", {
    data: {username, password},
    method: "POST",
  })
}

export function register(username, password) {
  return request("/auth/users/", {
    data: {username, password},
    method: "POST",
  })
}



「qrmenu_react/src/contexts/AuthContext.js」ファイルを編集します。


記述編集 【QRMenu/qrmenu_react/src/contexts/AuthContext.js】

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

import {signIn as signInApi, register as registerApi} from '../apis';

const AuthContext = createContext();

export const AuthProvider = ({ children }) => {
  const [token, setToken] = useState(localStorage.getItem("token"));
  const [loading, setLoading] = useState(false);

  const signIn = async (username, password, callback) => {
    setLoading(true);
    const response = await signInApi(username, password);
    console.log("response", response);

    if(response && response.auth_token) {
      localStorage.setItem("token", response.auth_token);
      setToken(response.auth_token);
      callback();

    }
    setLoading(false);
  }

  const signOut = () => {
    localStorage.removeItem("token");
    setToken("");
  }

  const register = async (username, password, callback) => {
    setLoading(true);
    const  response = await registerApi(username, password);
    if(response && response.id) {
      callback();
    }
    setLoading(false);
  }

  const value = {
    token,
    loading,
    signIn,
    signOut,
    register,

  }
  return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>
};
export default AuthContext;



「src/pages」フォルダに「Register.js」ファイルを新規作成します。
新規作成した「Register.js」ファイルを以下のように編集します。



新規作成 「QRMenu/qrmenu_react/src/pages/Register.js」

import { Button, Col, Form, Row, Card, Spinner } from "react-bootstrap";
import { React, useState, useEffect, useContext } from "react";
import { useHistory } from 'react-router-dom';

import { signIn } from '../apis';
import MainLayout from '../layouts/MainLayout';
import AuthContext from '../contexts/AuthContext';

const Register = () => {
  const [username, setUsername] = useState("");
  const [password, setPassword] = useState("");

  const history = useHistory();
  const auth = useContext(AuthContext);

  useEffect(() => {
    if(auth.token) {
      history.replace('/places');
    }
  });

  const onClick = () => {
    auth.register(username, password, () => history.replace("/places"));
  };

  return (
    <MainLayout>
        <Row className="justify-content-center">
          <Col lg={6} mg={8}>
            <Card>
              <Card.Body>
                <div className="form-title text-center">
                  <b>ユーザー登録</b>
                </div>
                <Form.Group>
                  <Form.Label>氏名</Form.Label>
                  <Form.Control
                    type="text"
                    placeholder="氏名を入力"
                    value={username}
                    onChange={(e) => setUsername(e.target.value)}
                  />
                  <Form.Label>パスワード</Form.Label>
                  <Form.Control
                    type="password"
                    placeholder="パスワードを入力"
                    value={password}
                    onChange={(e) => setPassword(e.target.value)}
                  />
                </Form.Group>
                <Button variant="standard" block onClick={onClick} disabled={auth.loading}>
                    {
                      auth.loading ? (
                        <Spinner
                          variant="standard"
                          as="apan"
                          animation="border"
                          size="sm"
                          role="status"
                          aria-hidden="true"
                        />
                      ) : (
                        "ユーザー登録"
                      )
                    }
                  </Button>                
              </Card.Body>
            </Card>
          </Col>
        </Row>
    </MainLayout>
  );
};
export default Register;



「qrmenu_react/src/router/App.js」ファイルに記述を追加します。


記述追加 【Desktop/QRMenu/qrmenu_react/src/router/App.js】

import { BrowserRouter, Switch, Route } from 'react-router-dom';
import { ToastContainer } from 'react-toastify';
import React from 'react';

import { AuthProvider } from '../contexts/AuthContext';
import PrivateRoute from './PrivateRoute';

import Home from '../pages/Home';
import Login from '../pages/Login';
import Register from '../pages/Register';
import Places from '../pages/Places';

function App() {
  return (
    <AuthProvider>
    <BrowserRouter>
      <Switch>
        <Route exact path='/'>
          <Home />
        </Route>
        <Route exact path='/login'>
          <Login />
        </Route>
        <Route exact path='/register'>
          <Register />
        </Route>        
        <PrivateRoute exact path='/places'>
          <Places />
        </PrivateRoute>        
      </Switch>
    </BrowserRouter>
    <ToastContainer />
    </AuthProvider>
  )
}

export default App;



「src/layouts/MainLayout.js」ファイルを編集します。


記述編集 【QRMenu/qrmenu_react/src/layouts/MainLayout.js】

import { Navbar, Nav, Container } from 'react-bootstrap';
import { useHistory } from 'react-router-dom';
import React, { useContext } from 'react';

import AuthContext from '../contexts/AuthContext';

const MainLayout = ({ children }) => {
  const history = useHistory();
  const auth = useContext(AuthContext);

  const onSignIn = () => {
    history.replace("/login");
    
  }

  const onRegister = () => {
    history.replace("/register");
    
  }

  const onSignOut = () => {
    auth.signOut();
    history.push("/login");
  }

  const goToPlaces =() => {
    history.push("/places");
  }

  return (
    <>
      <Navbar bg="dark" variant="dark" className="mb-4">
        <Navbar.Brand href="/">QRオーダーシステム</Navbar.Brand>

        <Nav>
          <Nav.Link onClick={goToPlaces}>飲食店</Nav.Link>
        </Nav>

        <Nav className="flex-grow-1 justify-content-end">
          {auth.token ? (
            <Nav.Link onClick={onSignOut}>ログアウト</Nav.Link>
          ) : (
            [
              <Nav.Link key={1} onClick={onSignIn}>ログイン</Nav.Link>,
              <Nav.Link key={2} onClick={onRegister}>ユーザー登録</Nav.Link>
            ]

          )}
          
        </Nav>
      </Navbar>
      <Container>{children}</Container>
    </>
  )
}

export default MainLayout;



ブラウザを確認します。
http://localhost:3000/register


ユーザー登録してみます。
パスワードは8文字以上必要です。

ユーザー登録
ユーザー登録



登録したユーザーでログインできるか確認します。

ログイン確認
ログイン確認



ログインできてPlacesページにリダイレクトするのを確認してください。

ログイン成功
ログイン成功



posticoでユーザー登録できていることを確認します。

postico確認
postico確認



↓↓クリックして頂けると励みになります。


[12 | Auth Context] << [ホーム] >> [14 | 飲食店登録実装]