React + Apollo Client  -Mutation ユーザー認証編-

 

このセクションではApollo Client + React でのMutationの使い方をユーザー認証と共に学習します。

 

Register.jsの実装

src/Register.jsを作成します。同時にルーティングの使用したいのでreact-router-domreact-routerをインストールします。

npm i react-router-dom react-router

pagesデイレクトリをつくりその中にLogin.jsRegister.jsTodoListing.jsを作成します。またgraphqlディレクトリにQueryやMutationを記述します。

src下はこのようになっています。トップページ(ここではhttp://localhost:3000)にTodoListing.jsを持ってきてTodoを表示します。

src
├── graphql
├── index.js
├── App.js
├── pages
  ├── Login.js
  ├── Register.js
  ├── TodoListing.js

   //src/App.js

   import { BrowserRouter as Router, Route, Switch} from 'react-router-dom'
   import Register from './pages/Register';
   import Login from './pages/Login';
   import TodoListing from './pages/TodoListing';
   
   function App() {
     return (
       <Router>
        <Switch>
          <Route path="/register" component={Register} />
          <Route path="/login" component={Login} />
          <Route path="/" exact component={TodoListing} />
        </Switch> 
       </Router>
     );
   }
   
   export default App;    
                    

上のようにApp.jsでルーティングをおこなっています。

先にMutationを扱う前にユーザー登録のためのフォームをpages/Register.jsからかいていきます。


   //  src/pages/Register.js

   import React, { useState } from 'react'

   function Register() {
       const [ username, setUsername ] = useState("")
       const [ email, setEmail ] = useState("")
       const [ password, setPassword ] = useState("")
       const onSubmit = (e) => {
           e.preventDefault();
       }
       return (
           <form onSubmit={onSubmit}>
            <input type="text" placeholder="username" onChange={(e) => setUsername(e.target.value)} value={username} />   
            <input type="email" placeholder="email" onChange={(e) => setEmail(e.target.value)} value={email} />   
            <input type="password" placeholder="password" onChange={(e) => setPassword(e.target.value)} value={password} /> 
            <button type="submit">register</button> 
           </form>
       )
   }
   
   export default Register       
        
                    

Reactをかいている人にとっては定番だと思うのでここでのuseStateやonClickの説明は省略します。ここではユーザーが書いたフォームがGraphQLの引数のargsの部分として送信されます。Queryのときと同様にuseMutationというReact Hookのひとつを使います。

graphqlディレクトリ下にqueriesmutationsディレクトリを作成しまずmutations下にregister.jsファイルを作成します。


// src/graphql/mutations/register.js

   import { gql } from "@apollo/client";

   export const USER_REGISTER = gql `
   mutation registerMutation($username: String!, $email: String!, $password: String!){
      register(username: $username, email: $email, password: $password){
          username
          email
      }
  }`

 まず前回と同様にgqlを使用してmutationを書いていきます。またここでは厳密に型付けとnull-ableな関数であるかを指定する必要があります。

 先ほどユーザー登録フォームを記述したpages/Register.jsにRegister(ユーザー登録)のMutationを実装していきます。


// pages/Register.js

import React, { useState } from 'react'
import { useMutation, gql } from '@apollo/client';
import { useHistory } from 'react-router';
import { USER_REGISTER } from '../graphql/mutations/register';

function Register() {
    const history = useHistory();
    const [ username, setUsername ] = useState("")
    const [ email, setEmail ] = useState("")
    const [ password, setPassword ] = useState("")
    const onSubmit = (e) => {
        e.preventDefault();
        register()
    }
    const [register] = useMutation(USER_REGISTER, {
        variables: {
            username,
            email,
            password
        },
        onCompleted: () => history.push('/login')
    })
    return (
        <form onSubmit={onSubmit}>
         <input type="text" onChange={(e) => setUsername(e.target.value)} value={username} />   
         <input type="email" onChange={(e) => setEmail(e.target.value)} value={email} />   
         <input type="password" onChange={(e) => setPassword(e.target.value)} value={password} /> 
         <button type="submit">register</button> 
        </form>
    )
}

export default Register

 src/graphql/mutations/register.jsに作成したUSER_REGISTERuseMutationに渡します。同時にユーザーがフォームで書いたユーザーネームなどのvariables(変数)もわたす必要があります。onCompletedはmutationが完了した後に実行する関数でここではユーザー登録後にログインを行いたいのでonCompleted: () => history.push('/login')としました。最後にonSubmitregister()を渡せば完了です。

 npm startでhttp://localhost:3000/registerにいって新たにユーザーを作成してみてください。無事に完了すれば/loginにとびます。

Login.jsの実装

 Login.jsRegister.js同様に src/pages下に作成していきます。そしてログインのMutationをsrc/graphql/mutations/login.jsを作成し、register同様に


// src/graphql/mutations/login.js

   import { gql } from "@apollo/client";

   export const USER_LOGIN = gql `
   mutation loginMutation($email: String!, $password: String!){
      login(email: $email, password: $password){
          username
          email
      }
  }`

// src/pages/Login.js

import React, { useState } from 'react'
import { useMutation, gql } from '@apollo/client';
import { useHistory } from 'react-router';
import { USER_LOGIN } from '../graphql/mutations/login';

function Login() {
    const history = useHistory();
    const [ email, setEmail ] = useState("")
    const [ password, setPassword ] = useState("")
    const onSubmit = (e) => {
        e.preventDefault();
        login()
    }
    const [login] = useMutation(USER_LOGIN, {
        variables: {
            email,
            password
        },
        onCompleted: () => history.push('/')
    })
    return (
        <form onSubmit={onSubmit}>  
         <input type="email" onChange={(e) => setEmail(e.target.value)} value={email} />   
         <input type="password" onChange={(e) => setPassword(e.target.value)} value={password} /> 
         <button type="submit">login</button> 
        </form>
    )
}

export default Login
                    

Registerのときとほとんど同じコードですが今回は完了したらhttp://localhost:3000のトップページにかえってくるようにします。

最後にログインしているユーザーをregister.jslogin.jsにきたときにトップページに返すようにコードを加えます。ここではバックエンド編で実装したmeQueryというログインしているユーザー情報を取り出すQueryを使います。

まずはgraphql/queries下にme.jsというファイルを作成し、以下のQueryを記述します。


// src/graphql/queries/me.js

   import { gql } from "@apollo/client";

   export const ME_QUERY = gql `
   query Me {
    me {
      id
      username
      email
    }
  }
  }`

register.jslogin.jsに以下のコードをたします。ページにアクセスしたときにログインしているかどうかを確かめています。


 iport { ME_QUERY } from '../graphql/queries/me';

 .....

 const { loading, data } = useQuery(ME_QUERY)

 useEffect(() => {
 if(!loading && data.me){
    history.push('/')
 } 
 },[loading, data, history])
                    

足早に実装したので一度src/pages/Register.jssrc/pages/Login.jsを確認して自分のコードと照らし合わせてみてください。

ここでユーザー認証のユーザー登録とログインをパートを終了します。次からはTodoのCRUDのCREATE、UPDATE、DELETEを実装します。