「Next.jsでつくるフルスタックアプリ後編」の感想・備忘録1

スポンサーリンク

点数

80点

感想

前編で作成したAPIを使用するためのページをNext.jsで作成していく、という内容だった。

特に複雑な処理もなく、問題なく最後まで読み終えることができた。

ユーザー関連ページ

ユーザー登録ページの作成

  1. mkdir pages/user/
  2. touch pages/user/register.js
  • Reactではform送信はonSubmitで処理するので、action, methodはformタグに書かない。
  • フォームはJSON.stringify()でJSONにして送信する。
  • fetch(), json()はPromiseを返却するのでawaitを付ける
import { useState } from 'react'

const Register = () => {
  const [name, setName] = useState('');
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const handleSubmit = async (e) => {
    e.preventDefault();
    try {
      const response = await fetch('http://localhost:3000/api/user/register', {
        method: 'POST',
        headers: {
          'Accrpt': 'application/json',
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          name: name,
          email: email,
          password: password,
        })
      });
      const json = await response.json();
      alert(json.msg);
    } catch (err) {
      alert('登録失敗');
    }
  };
  return (
    <>
      <h1>ユーザー登録</h1>
      <form onSubmit={handleSubmit}>
        <p>name: <input type="text" name="name" value={name} onChange={e=>setName(e.target.value)} required /></p>
        <p>email: <input type="text" name="email" value={email} onChange={e=>setEmail(e.target.value)} required/></p>
        <p>password: <input type="text" name="password" value={password} onChange={e=>setPassword(e.target.value)} required/></p>
        <p><button type="submit">登録</button></p>
      </form>
    </>
  )
};
export default Register;

ログインページの作成

  1. touch pages/user/login.js
import { useState } from 'react'

const Login = () => {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const handleSubmit = async (e) => {
    e.preventDefault();
    try {
      const response = await fetch('http://localhost:3000/api/user/login', {
        method: 'POST',
        headers: {
          'Accrpt': 'application/json',
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          email: email,
          password: password,
        })
      });
      const json = await response.json();
      localStorage.setItem('token', json.token); // 成功時のみ保存する場合は if (response.ok) {}で囲む必要あり
      alert(json.msg);
    } catch (err) {
      alert('ログイン失敗');
    }
  };
  return (
    <>
      <h1>ログイン</h1>
      <form onSubmit={handleSubmit}>
        <p>email: <input type="text" name="email" value={email} onChange={e=>setEmail(e.target.value)} required/></p>
        <p>password: <input type="text" name="password" value={password} onChange={e=>setPassword(e.target.value)} required/></p>
        <p><button type="submit">ログイン</button></p>
      </form>
    </>
  )
};
export default Login;

アイテムページ

全アイテム表示ページの作成

  1. mkdir pages/item/
  2. touch pages/item/index.js
import Link from "next/link";

const Index = (props) => {
  return (
    <>
      { props.allItems.map(item=> {
        return <p key={item._id}><Link href={`item/${item._id}`}>{item.title}</Link>: {item.description}: {item.price}: {item.email}</p>
      })}
    </>
  )
};
export default Index;
export const getServerSideProps = async () => {
  const response = await fetch('http://localhost:3000/api/item/readall');
  const allItems = await response.json();
  return {
    props: allItems
  }
};

詳細ページの作成

  1. touch pages/item/[id].js
  • ルートパラメータはcontext.queryから取得可能
import Link from "next/link";

const SingleItem = (props) => {
  return (
    <>
      <h1>{props.item.title}</h1>
      <h2>{props.item.description}</h2>
      <h3>{props.item.price}</h3>
      <h3>{props.item.email}</h3>
      <Link href={`/item/update/${props.item._id}`} style={{marginRight: '10px'}}>編集</Link>
      <Link href={`/item/delete/${props.item._id}`} style={{marginRight: '10px'}}>削除</Link>
      <Link href="/item">一覧へ戻る</Link>
    </>
  )
};
export default SingleItem;
export const getServerSideProps = async (context) => {
  const response = await fetch(`http://localhost:3000/api/item/${context.query.id}`);
  const item = await response.json();
  return {
    props: item
  }
};

作成ページの作成

  1. touch pages/item/create.js
  • 前編にてutils/auth.jsでconst token = req.headers.authorization.split(' ')[1];としているので、HTTPヘッダにAuthorizationを付与する
  • JWTではトークンを「Bearer xxxxxxxxxx」とするのが慣習である
import { useState } from 'react'

const CreateItem = () => {
  const [title, setTitle] = useState('');
  const [description, setDescription] = useState('');
  const [price, setPrice] = useState('');
  const handleSubmit = async (e) => {
    e.preventDefault();
    try {
      const response = await fetch('http://localhost:3000/api/item/create', {
        method: 'POST',
        headers: {
          'Accrpt': 'application/json',
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${localStorage.getItem('token')}`
        },
        body: JSON.stringify({
          title: title,
          description: description,
          price: price,
        })
      });
      const json = await response.json();
      alert(json.msg);
    } catch (err) {
      alert('登録失敗');
    }
  };
  return (
    <form onSubmit={handleSubmit}>
      <h1>アイテム作成</h1>
      <p>title: <input type="text" name="title" value={title} onChange={e=>setTitle(e.target.value)} required/></p>
      <p>description: <input type="text" name="description" value={description} onChange={e=>setDescription(e.target.value)}/></p>
      <p>price: <input type="text" name="price" value={price} onChange={e=>setPrice(e.target.value)}/></p>
      <p><button type="submit">投稿</button></p>
    </form>
  )
};
export default CreateItem;

コメント