iT邦幫忙

2024 iThome 鐵人賽

DAY 17
0
佛心分享-SideProject30

用 Next.js 實作屋況查詢評估專家網站系列 第 17

[Day 17] 環境建置-將第一支API串接上去吧

  • 分享至 

  • xImage
  •  

前言:前幾天我分享了如何從自己開發的第一支使用者註冊GraphQL API,到前端Next.js應用串接所需的套件安裝及使用方式。今天,我們將開始將這個API串接到我們的應用程式中,讓它真正運作起來。

第一步:在Next.js專案上建立好app路由

建立路由目錄和頁面文件

在app資料夾下建立sign-in資料夾
在sign-in資料夾下建立page.tsx文件
使用快捷指令rfc建立頁面模板雛形

在page.tsx文件中輸入rfc來建立React函式元件的模板雛形。這樣可以減少輸入起始手勢的時間,快速建立頁面基礎。

 

第二步:安裝並配置必要的套件

import { ApolloClient, InMemoryCache, createHttpLink } from "@apollo/client";
import { setContext } from "@apollo/client/link/context";
// NOTE zustand
import useTokenStore from "@/zustand/useTokenStore";
export const uri =
  process.env.NODE_ENV === "production"
    ? "uri"
    : "uri";

const httpLink = createHttpLink({
  uri,
});

const authLink = setContext((_, { headers }) => {
  // const token = "";
  const token = useTokenStore.getState().token;
  const authorization = token ? `Bearer ${token}` : "";
  return {
    headers: {
      ...headers,
      authorization,
    },
  };
});

const cache = new InMemoryCache({
  typePolicies: {
    Query: {},
  },
});

const client = new ApolloClient({
  link: authLink.concat(httpLink),
  cache,
});
export default client;

第三步:將Apollo Client提供給Next.js應用

在app資料夾下創建ApolloProviderWrapper.tsx文件,來設置ApolloProvider

import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";
import AppHeader from "@/components/Layouts/Basic/AppHeader";
import AppFooter from "@/components/Layouts/Basic/AppFooter";
import { noto_sans_tc, noto_sans_mono, noto_serif_tc } from "@/fonts";
import ApploProvider from "@/provider/Applo";  


const inter = Inter({ subsets: ["latin"] });
import clsx from "clsx";
export const metadata: Metadata = {
  title: "",
  description: "",
};
export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="zh-TW">
      <ApploProvider>
        <body
          className={clsx(
            noto_sans_tc.className,
            noto_sans_tc.variable,
            noto_serif_tc.variable,
            noto_sans_mono.variable,
            inter.className
          )}
        >
          <AppHeader />
          <div className=" flex-1">
            {children}
          
          </div>
          <AppFooter />
        </body>
      </ApploProvider>
    </html>
  );
}

第四步:在sign-in頁面中使用GraphQL API

在page.tsx中添加GraphQL註冊請求

由於Next.js預設頁面是採用 use server,不過這個頁面有使用到狀態,以及表單的處理,所以則需要在頁面最開頭加入 use client 宣告這個頁面客戶端渲染

"use client";
import React from "react";
import MemberLayout from "@/components/Layout/member";
import SectionTitle from "@/components/SectionTitle";
import { Controller, SubmitHandler, useForm } from "react-hook-form";
import { SchemaType, resolver, defaultValues } from "@/form/signIn";
import useMutaionLogin from "@/apollo/hooks/useMutationSignIn";
 
import { useRouter } from "next/navigation";
export default function Page() {
  const { handleSubmit, control, reset } = useForm<SchemaType>({
    resolver,
    defaultValues,
  });
  const { push } = useRouter();
  const [Mutation, { loading }] = useMutaionLogin();
 
  return (
    <MemberLayout>
      <div className="min-h-screen h-full py-10 container">
        <SectionTitle title="登入" subTitle="Login" />
        <div className=" w-2/3 m-auto h-2/3 flex justify-center items-center">
          <form onSubmit={handleSubmit(_onSubmit)}>
            <label className="input input-bordered flex items-center gap-2 mb-3">
              <svg
                xmlns="http://www.w3.org/2000/svg"
                viewBox="0 0 16 16"
                fill="currentColor"
                className="w-4 h-4 opacity-70"
              >
                <path d="M8 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6ZM12.735 14c.618 0 1.093-.561.872-1.139a6.002 6.002 0 0 0-11.215 0c-.22.578.254 1.139.872 1.139h9.47Z" />
              </svg>
              <label htmlFor="username">帳號</label>
              <Controller
                control={control}
                name="username"
                render={({ field, fieldState: { error } }) => {
                  return (
                    <>
                      <input
                        {...field}
                        id="username"
                        type="text"
                        className="grow input-lg input-primary"
                        placeholder=""
                      />
                      {error?.message && (
                        <span className=" text-rose-600">{error?.message}</span>
                      )}
                    </>
                  );
                }}
              />
            </label>
            <label className="input input-bordered flex items-center gap-2 mb-3">
              <svg
                xmlns="http://www.w3.org/2000/svg"
                viewBox="0 0 16 16"
                fill="currentColor"
                className="w-4 h-4 opacity-70"
              >
                <path
                  fillRule="evenodd"
                  d="M14 6a4 4 0 0 1-4.899 3.899l-1.955 1.955a.5.5 0 0 1-.353.146H5v1.5a.5.5 0 0 1-.5.5h-2a.5.5 0 0 1-.5-.5v-2.293a.5.5 0 0 1 .146-.353l3.955-3.955A4 4 0 1 1 14 6Zm-4-2a.75.75 0 0 0 0 1.5.5.5 0 0 1 .5.5.75.75 0 0 0 1.5 0 2 2 0 0 0-2-2Z"
                  clipRule="evenodd"
                />
              </svg>
              <label htmlFor="password">密碼</label>
              <Controller
                control={control}
                name="password"
                render={({ field, fieldState: { error } }) => {
                  return (
                    <>
                      <input
                        {...field}
                        type="password"
                        id="password"
                        className="grow"
                      />
                      {error?.message && (
                        <span className=" text-rose-600">{error?.message}</span>
                      )}
                    </>
                  );
                }}
              />
            </label>

            <button type="submit" className="btn btn-primary">
              登入
            </button>
          </form>
        </div>
      </div>
    </MemberLayout>
  );
}


現在,你的Next.js應用已經能夠串接到GraphQL API,並且可以進行使用者註冊了。這樣,你就完成了從API開發到前端串接的整個流程。希望這個過程能夠對你有所幫助!

參考資源
JWT Token
Next.js
Layout Children Props


上一篇
[Day 16] 環境建置-Apollo Client
下一篇
[Day 18] 表單套件使用
系列文
用 Next.js 實作屋況查詢評估專家網站30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言