TIL

240927

playhong 2024. 9. 27. 21:19

FACTS(사실, 객관) : 내가 한 일

next.js

Next.js의 핵심기능은 캐싱이라고 할 수 잇다

=> 여기까지만 알겠고 하나두 이해가 안감 

 

Parellel & Intercepting Routes

=> 같은 레이아웃 안에서 여러 페이지를 동시/조건부 렌더링 할 수 있게 해줌 (대시보드/소셜사이드의 피드같은 동적인 섹션)

탭이나 모달에서 많이 사용함.

여기까지만 따라가고 이해가 안감..

 

라우팅 규칙

(.) : 동일한 레벨의 세그먼트

(..) : 한 레벨 위의 세그먼트

(..)(..) : 두 레벨 위의 세그먼트 

(...) : 루트 디렉토리에서 시작하는 모든 세그먼트

 

제어컴포넌트

리액트에 의해 값이 제어되는 입력 form 엘리먼트를 제어컴포넌트라고 함.

input의 onChange등을 모두 state로 관리하는 컴포넌트 

setState가 실행되면서 리렌더링됨.

대부분의 케이스에 사용가능 

"즉각적으로, 실시간 값에 대한 피드백이 필요하다!"

 

비제어컴포넌트

리엑트에서 값이 제어되지 않는 컴포넌트

리렌더링되지 않음

일회용 정보검색, 제출 시 값 검증등에서만 사용할 수 있고 나머지엔 제한적임.

"즉각적인 피드백 보단 제출시에 값이 필요하다, 불필요한 렌더링과 값 동기화가 싫다! 성는이 조금 더 중요할 거 같다!"

 

폼 관리 라이브러리

Form에 있는 Input들을 최대한 최적화 해서 사용할 수 있는 방법 => React Hook Form

비제어 컴포넌트를 기반드로 한 Form 관리 및 검증 라이브러리.

공식홈페이지에서도 리렌더링을 격리했다고 강조하고 있음!

(https://react-hook-form.com/)

 

useState를 사용하면 해당 컴포넌트가 지속적으로 리렌더링됨

이게 무조건 나쁜건 아님! 값을 새로 업데이트 하기 위해 실시간으로 반영되는 값을 가지고 오기 위해서는 필수적으로 리렌더링을 해야 유저가 실시간으로 변경되는 값을 볼 수 있고, 검증로직을 사용하고 있다면 값이 실시간으로 변경되어줘야 "비밀번호가 틀렸습니다"같은 검증 메시지를 보여주기에 용이하므로!

 

하지만!

유효성 검사가 필요한 상황이 아님에도 계속해서 리렌더링되는 것은 좀..

=> 이럴 때 React Hook Form 사용하는 것.

 

설치

yarn add react-hook-form

 

사용

const { register, handleSubmit, formState } = useForm({
  mode: "onChange", // Form안에 있는 값을 validating 하거나 tracking하는 시점 설정.
  defaultValues: { // 디폴트값 설정
    email: "123",
    password: "",
  }
}); // 이렇게 3개 import

const onSubmit = (value: FieldValues) => {}

//FieldValues => react hook form 안에 있는 타입.

return(
  <form onSubmit={(e) => handleSubmit(onSubmit)(e)}>
  	<input
      {...register('email', {
        required: {
          value: true,
          message: "email required",
          // 필수요소로 지정하고 안적으면 message띄움
        },
        
        pattern:{
          value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
          message: "invalid email address"
          //value를 통과하지 못하면 message를 띄울거야~ 라는 뜻
        }
      })}
      type="email"
    />
    {formState.errors.email && (
      <span>{formState.errors.email.message}</span>
    )} 
    {/* => formState.errors에 email이 존재한다면 formState.errors.email.message를 띄워줌 */}
  </form>
)

handleSubmit

폼 안에 넣어주는 함수

register

Input을 등록하는 함수
formState

객체형태의 값

defaultValues(디폴트로 넣는 값), dirty(defaultValues로 넣어놓은 값이 변경됐는지 안됐는지 알아보는 필드 => 수정할 때 용이), errors(error가 되는 값을 넣어줬을 때 feild가 변경이됨.), valid가 제일 중요.

 

타입 검증 라이브러리 Zod

만들어놓은 schema(스키마)를 타입스크립트 기반으로 validation(확인) 해준다는 뜻

스키마란? 어떤 객체를 구성하는 정의서 같은 느낌으로 생각하면 됨

익숙하진 않을건데 사용법은 간단하다.. => (어렵다는 뜻..?)

(https://zod.dev/)

 

설치

yarn add zod

 

사용

import { z } from "zod" // zod로 부터 import 받은 객체로 schema를 만들 수 있다.

const signInSchema = z.object({
  email: z.string().email({ message: "invalid email" }),
  password: z.string(),
})
// z.object라는 함수를 통해 스키마를 만들어줄것임.
// 이 signInSchema를 통해 타입 검증을 할것이다.

const SignInForm = () => {
    const { register, handleSubmit, formState } = useForm({
      mode: "onChange",
      defaultValues: {
        email: "123",
        password: "",
      }
    });

    const onSubmit = (value: FieldValues) => {
      signInSchema.parse(value)
    } // 스키마에 parse라는 함수를 불러오고 뒤에 검증하고 싶은 객체를 넣어주면 됨.
	

    return(
      <form onSubmit={(e) => handleSubmit(onSubmit)(e)}>
        <input
          {...register('email', {
            required: {
              value: true,
              message: "email required",
            },

            pattern:{
              value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
              message: "invalid email address"
            }
          })}
          type="email"
        />
        {formState.errors.email && (
          <span>{formState.errors.email.message}</span>
        )} 
      </form>
    )
    }

 

타입스크립트는 컴파일 타임에 모두 자바스크립트로 변경되는데ㅡ,

zod는 내부적으로 여러가지 타입 검사가 들어가 있어서 런타임에도 즉, 자바스크립트로 변경된 이후에도 타입에 관련된 error를 나타내 줌. => 예기치 못한 타입이 들어왔을 때 타입스크립트로 검증할 수 없는 런타임 순간에 예기치 못한 타입이 외부로부터 들어오는 경우에도 안전하게 타입검증을 할 수 있다!!

 

근데 zod를 단독으로 사용하는것이 아님!! 

react hook form 안에 required, validate 같은 것을 넣지 않더라도 자동으로 zod와 연동돼서 validation을 해줬으면 좋겠다!!

=> 이때 필요한게 resolver.

 

설치

yarn add @hookform/resolvers

 

사용

import { zodResolver } from "@hookform/resolvers/zod"; // zodResolver 임포트
import { FieldValues, useForm } from "react-hook-form";
import { z } from "zod"

const signInSchema = z.object({
  email: z
    .string({
      message: "email required" // required message도 내부적으로 정해줄 수 있음!
    })
    .email({ message: "invalid email" })
    .min(1, {
      message: "email required"
    }),
    .max(10, {
      message: "too long"
    }) // min/max처럼 길이를 확인할 수 있는 함수들도 내장되어 있음!
  password: z.string(),
})

const SignInForm = () => {
    const { register, handleSubmit, formState } = useForm({
      mode: "onChange",
      defaultValues: {
        email: "123",
        password: "",
      },
      resolver: zodResolver(signInSchema)
    });

    const onSubmit = (value: FieldValues) => {
      signInSchema.parse(value)
    } 
	

    return(
      <form onSubmit={(e) => handleSubmit(onSubmit)(e)}>
        <input
          {...register('email')} <= 옵션 넣어줬던 것 다 지워도 됨!
          type="email"
        /> 
        {formState.errors.email && (
          <span>{formState.errors.email.message}</span>
        )} 
      </form>
    )
    }

 

원하는 유효성 검사를 자유롭게 넣을 수 있고 그걸 한 군데에서 전부 관리하고 업데이트도 위임할 수 있다!!! <정말 강력한 기능!

 

middleware.ts

Next.js에 어떤 요청을 보낼 때 (API 라우트나 app 라우트 요청을 보낼 때) 요청을 가로채서 Next.js 서버에 미처 요청이 들어오기 전에 이 앞에서 MiddleWare가 한번 이 요청을 검수해서 넘겨줄 수 있게끔 하는 기능.

로깅 보안을 도와주는 것.

 

먼저 yarn dev로 프로젝트 실행

yarn server로 서버도 실행해 준 다음

src폴더 혹은 app디렉토리가 존재하는 root폴더에  middleware.ts파일을 만들기.

이 파일은 프로젝트당 한개만 생성이 가능함!

import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

// This function can be marked `async` if using `await` inside
export function middleware(request: NextRequest) {
  return NextResponse.redirect(new URL('/home', request.url));
}

export const config = {
  matcher: '/about/:path*',
}; // 어떤 페이지에서 미들웨어를 실행시킬지 결정해주는 matcher 설정

 

middleware

 

redirect => 사용자를 해당 /home(다른 페이지로 수정할 수 있음!) 으로 리다이렉트 시킴!

rewrite => redirect와 같은데, url노출이 안됨! /home으로 가더라도 http://localhost:3000이런식으로 보임!  

 

 

matcher

 

'/about/:path*' => /about하고 /뒤에 있는 모든 path를 잡아 middleware를 실행시켜주겠다는 뜻! 

['/about/:path*', '/dashboard/:path*'], => matcher를 복수(배열)형태로 넣을 수 있음! (about 뒤에 잇는 모든값과 dashboard뒤에 있는 모든 값을 가져와 실행시켜 주겠다는 뜻!)

'/((?!api|_next/static|_next/image|favicon.ico).*)' => 정규식도 사용가능! api나 next/static, next/image, favicon과 같은 것들을 제외하고 모두 매칭 시켜줘! 라는 뜻! (원하지 않는 콘텐츠를 정규식으로 걸러 실행할 수 있음!)

import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

// This function can be marked `async` if using `await` inside
export function middleware(request: NextRequest) {
  // 검증을 위한 비동기 함수
  await fetch(""); 
  //특정 라우트에 실제 검증을 하는 비동기 함수를 작성하더라도 해당 함수는 서버에서 비동기로 동작하기 때문에 원활히 동작함!
  
  const isLogin = false;
  
  if(!isLogin && request.nextUrl.pathname.includes('/cart')){
    return NextResponse.redirect(new URL('/sign-in', request.url));
  } // 특정 조건을 성립하는 path인지 등을 확인해서 return문을 따로 작성하면 이것도 그대로 동작함! 
  // (로그인 하지 않은 유저가 cart에 접근하려 한다면 로그인페이지로 보내는 로직)

  return NextResponse.redirect(new URL('/home', request.url));
}

export const config = {
  matcher: '/about/:path*',
}; // 어떤 페이지에서 미들웨어를 실행시킬지 결정해주는 matcher 설정

 

-- 4-6 11:26


FEELINGS(느낌, 주관) : 나의 감정적인 반응, 느낌

 


FINDINGS(배운 것) : 그 상황으로부터 내가 배운 것, 얻은 것

 


FUTURE(미래) : 배운 것을 미래에는 어떻게 적용할 지

 

'TIL' 카테고리의 다른 글

240930  (0) 2024.09.30
240928  (0) 2024.09.28
240926  (0) 2024.09.26
240925  (0) 2024.09.25
240924  (0) 2024.09.24