[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でユーザー登録できていることを確認します。
↓↓クリックして頂けると励みになります。
[12 | Auth Context] << [ホーム] >> [14 | 飲食店登録実装]