Computer >> 컴퓨터 >  >> 프로그램 작성 >> Redis

가장 미니멀한 Next.js TODO 앱

이 기사에서는 Serverless Next.js 기반 TODO 애플리케이션을 빌드합니다. 미니멀리스트가 되도록 최선을 다하겠습니다. 데이터베이스 연결이 없습니다. Next.js 이외의 추가 종속성은 없습니다. 버튼이 없을 것입니다. 게다가 minimalism 시원하고 깨끗합니다. 게으른 개발자이기 때문에 좋아합니다 :)

데이터베이스 연결을 피하는 이유는 무엇입니까?

Next.js는 프런트 엔드 개발자가 전체 스택 응용 프로그램을 개발할 수 있도록 하는 최신 프레임워크입니다. 서버리스 기능은 Next.js 개발자의 백엔드 개발을 단순화하는 데 중요한 역할을 합니다. 아시다시피 서버리스 함수는 상태 비저장 특성으로 인해 데이터베이스 연결을 좋아하지 않습니다. 서버리스 함수 내부의 데이터베이스 연결 문제의 예는 여기와 여기를 참조하십시오.

REST는 답입니다

REST를 사용하면 클라이언트와 서버가 세션 정보 없이 통신할 수 있습니다. 이러한 상태 비저장 및 단순한 특성으로 인해 REST는 서버리스 환경을 위한 완벽한 통신 프로토콜입니다. REST를 사용하여 Upstash Redis에 액세스합니다.

프로젝트 스택

  • 프론트엔드:Next.js
  • 백엔드:Vercel 함수
  • 데이터베이스:REST API를 사용한 Upstash Redis

데모 보기:https://nextjs-todo-zeta.vercel.app/

코드 참조:https://github.com/upstash/examples/tree/master/nextjs-todo

프로젝트 설정

Next.js 앱 만들기:npx create-next-app

AWS-US-EAST-1 리전에서 Upstash Redis 데이터베이스를 생성하고 REST URL과 토큰을 복사합니다.

프로젝트는 3개의 API 엔드포인트가 있는 단일 페이지 애플리케이션입니다.

  • pages/api/list.js:TODO 항목을 나열합니다.
  • pages/api/add.js:TODO 항목을 추가합니다.
  • pages/api/remove.js:TODO 항목을 제거합니다.

코드

아래와 같이 pages/api/list.js를 추가하십시오.

export default async (req, res) => {
  const token = "REPLACE_YOUR_TOKEN";
  const url = "https://REPLACE_YOUR_ENDPOINT/lrange/todo/0/100?_token=" + token;

  return fetch(url)
    .then((r) => r.json())
    .then((data) => {
      let result = JSON.stringify(data.result);
      return res.status(200).json(result);
    });
};

아래와 같이 페이지/api/add.js를 추가합니다.

export default async (req, res) => {
  if (!req.query.todo) {
    return res.status(400).send("todo parameter required.");
  }
  let todo = encodeURI(req.query.todo);

  const token = "REPLACE_YOUR_TOKEN";
  const url =
    "https://REPLACE_YOUR_ENDPOINT/lpush/todo/" + todo + "?_token=" + token;

  return fetch(url)
    .then((r) => r.json())
    .then((data) => {
      let result = JSON.stringify(data.result);
      return res.status(200).json(result);
    });
};

아래와 같이 pages/api/remove.js를 추가하십시오.

export default async (req, res) => {
  if (!req.query.todo) {
    return res.status(400).send("todo parameter required.");
  }
  let todo = encodeURI(req.query.todo);

  const token = "REPLACE_YOUR_TOKEN";
  const url =
    "https://REPLACE_YOUR_ENDPOINT/lrem/todo/1/" + todo + "?_token=" + token;

  return fetch(url)
    .then((r) => r.json())
    .then((data) => {
      let result = JSON.stringify(data.result);
      return res.status(200).json(result);
    });
};

페이지/index.js를 아래와 같이 업데이트:

import Head from "next/head";
import Image from "next/image";
import styles from "../styles/Home.module.css";
import { useEffect, useState } from "react";

export default function Home() {
  const [data, setData] = useState([]);
  const [loading, setLoading] = useState(false);
  const [todo, setTodo] = useState("");
  let changeHandler = (event) => {
    setTodo(event.target.value);
  };

  let addTodo = (event) => {
    setLoading(true);
    event.preventDefault();
    fetch("/api/add?todo=" + todo)
      .then((res) => res.json())
      .then((data) => {
        loadTodos();
      });
  };

  let removeTodo = (rtodo) => {
    setLoading(true);
    fetch("/api/remove?todo=" + rtodo)
      .then((res) => res.json())
      .then((data) => {
        loadTodos();
      });
  };

  let loadTodos = () => {
    console.log("load todos");
    fetch("/api/list")
      .then((res) => res.json())
      .then((data) => {
        setData(data);
        setLoading(false);
      });
  };

  useEffect(() => {
    setLoading(true);
    loadTodos();
  }, []);

  if (!data) return "Loading...";
  return (
    <div className={styles.container}>
      <Head>
        <title>Next.js TODO APP</title>
        <meta name="description" content="Generated by create next app" />
        <link rel="icon" href="/favicon.ico" />
      </Head>

      <main className={styles.main}>
        <div className={styles.grid}>
          <h1 className={styles.title}>
            TODO App with{" "}
            <a href="https://blog.upstash.com/nextjs-todo">Next.js!</a>
            <br />
            <br />
          </h1>
          {loading ? (
            <a href="#" className={styles.card}>
              <img src="/loader.gif" />
            </a>
          ) : (
            <form className={styles.cardForm} onSubmit={addTodo}>
              <input
                className={styles.cardInput}
                type="text"
                name="todo"
                onChange={changeHandler}
                placeholder="Enter your exciting TODO item!"
              />
            </form>
          )}

          {data.map((item) => (
            <a
              href="#"
              onClick={() => removeTodo(item)}
              className={styles.card}
            >
              <p>{item}</p>
            </a>
          ))}
        </div>
      </main>

      <footer className={styles.footer}>
        <a
          href="https://blog.upstash.com/nextjs-todo"
          target="_blank"
          rel="noopener noreferrer"
        >
          Powered by{" "}
          <span className={styles.logo}>
            <Image src="/logo.png" alt="Upstash Logo" width={87} height={25} />
          </span>
        </a>
      </footer>
    </div>
  );
}

보시다시피 후크를 사용하는 기본 React 애플리케이션입니다. API와 상호작용하는 3가지 메소드가 있습니다:addTodo, removeTodo 및 loadTodos.

그리고 마지막으로 여기와 같이 styles/Home.module.css 파일을 업데이트합니다.

실행 및 배포

npm run dev를 사용하여 로컬에서 프로젝트 실행 . 모든 것이 괜찮아 보이면 vercel을 실행하여 프로젝트를 배포할 수 있습니다. 프로젝트 폴더에서. Vercel은 API 기능을 위한 서버리스 기능을 생성합니다. Vercel 함수의 기본 지역은 US-EAST-1이므로 동일한 지역에 데이터베이스를 만들었습니다.

참고

  • 데이터베이스 토큰을 Vercel 환경 변수에 보관하는 것이 더 안전합니다.
  • 서버리스 기능과 Redis 데이터베이스를 같은 지역에 유지하는 것이 성능에 가장 좋습니다.
  • REST API 대신 Redis 클라이언트를 사용할 수 있습니다. 하지만 앞서 언급했듯이 데이터베이스 연결은 서버리스 기능 내부에서 문제를 일으킬 수 있습니다. 또한 Upstash REST API와 기본 API 사이에 큰 성능 차이를 발견하지 못했습니다.