MSW (Mock Service Worker)

- API가 아직 준비되지 않았을 때 가상의 API 서버를 사용하여 진짜 API 통신하는 것처럼 프론트엔드 개발을 진행할 수 있다.

- 내 마음대로 에러를 발생시키는 응답을 낼 수도 있다.

 

env 파일

.env 파일에 NEXT_PUBLIC_API_MOCKING=enabled 등으로 셋팅하여 배포용 env에는 false, 개발용 env에는 enabled 해두어서 개발 환경일 때에만 MSW를 실행하게끔 하면 된다.

NEXT_PUBLIC으로 시작하는 환경변수 -> 브라우저에서 접근 가능하다!!

컴포넌트 파일에서 import하여 사용할 수 있음.

 

NEXT_PUBLIC이 없다면?

서버에서 접근 가능하고 브라우저에서 접근 불가.

 

브라우저는 개발자 도구를 통해 코드가 확인이 가능하기 때문에 공개가 되어도 되는 값들만 NEXT_PUBLIC을 사용.

비밀키 같은건 NEXT_PUBLIC 지우자.

 

 

 Server Actions 사용하기

1. 서버 컴포넌트에서 ServerActions 사용하기

- 보통 React에서는 회원가입 같은 form을 개발할 때, useState, onClick 등 클라이언트 컴포넌트에서 사용해야하는 hooks들이 있어서 컴포넌트 전체를 'use client' 해야하는데 이런 form 페이지도 Server client에서 진행이 가능하다.

 

- 우선 뒤로가기 같은 버튼은 Client Component로 빼주고

- html / js에서 사용하던 form 태그와 butotn submit을 사용하는 것이다.

서버에서 받을 수 있게 각 input 필드마다 name 속성을 넣어주고

<form action={submit}>

const submit = (formData: FormData) => {

  'use server'

 

  // 여기에 작성하는 코드는 서버에서 실행되기 때문에 브라우저에 노출되지 않는다.

}

 

이렇게 진행하면 클라이언트 컴포넌트로 변환하지 않아도 서버 컴포넌트에서 폼 가입을 진행할 수 있다.

 

 

2. 클라이언트 컴포넌트에서 ServerActions 사용하기

파일 하나 따로 빼서 'use server' 설정

그리고 그 파일을 client component에 import

 

React에서 제공하는 유용한 기능

react-dom의 useFormState, useFormStatus

ㄴ form을 제출하는 동안 pending 상태인지 등을 제공한다.

ㄴ pending이면 버튼을 disabled 시킬 수 있다.

 

 

 

Next-Auth (Auth.js)

Next에서 인증 관련된 기능을 구현할 때 주로 사용하는 라이브러리!

ㄴ 구글 로그인, 카카오로그인, 네이버로그인, 페이스북 로그인 등 간편 로그인을 제공

ㄴ 일반 로그인(아이디/패스워드)도 당근 지원한다.

 

Next Auth의 미들웨어를 사용해서 로그인 해야만 접근 가능한 페이지를 관리할 수도 있다.

 

Next Auth로 인증을 진행하면 next-auth/react 의 useSession()을 통해 로그인 된 유저의 정보를 가져올 수 있다.

유저의 정보가 없다면? 로그인 되어있지 않다는 것.

=> 로그인 여부에 따라 화면을 다르게 표시할 수도 있다.

 

Next Auth로 로그인하면 cookie에 session token이 생기는데, 이렇게 쿠키에 토큰을 넣어두면 csrf 공격을 받을 수 있다.

(공격자가 토큰 탈취해서 나인것처럼 로그인 하는 것)

근데 Next Auth에서 그 점은 방어해줘서 안전하다!

 

 

 

 

React-Query

클라이언트 상태관리

데이터 fetch 대표적인 라이브러리

서버로터 받은 데이터를 넘겨받음

리액트쿼리를 사용하여 인피니트 스크롤링도 가능

 

DevTool도 사용가능하다. 대신 local 개발환경에서만 사용가능하도록 설정하자.

Provider 설정을 통해 특정 범주안의 컴포넌트들 모두 react query를 사용할 수 있게 한다.

=> Query Client 먼저 만들기~

const queryClient = new QueryClient();

 

fetch(axios) + react-query 조합으로 많이 사용하는 듯 하다.

 

Next에서는 fetch에 대해 캐싱기능이 있다.

특정 상황에서 캐시 무효화를 하기 위해 revalidateTag나 revalidatePath를 사용할 수 있다.

 

페이지 접근 -> 서버에서 fetch 된 데이터와 함께 html 파일을 만들어줌 -> 클라이언트가 받아서 처리 (dehydrate?)

 

Redux vs React-Query를 쓰는가?

- React-Query 핵심: 서버의 데이터를 가져오는 것

ㄴ 잘하는 기능: 캐싱

ㄴ 캐싱을 왜 잘하면 좋은가?

ㄴ 캐싱은 트래픽 관리와도 관련이 있다. 캐싱을 하지 않으면 매번 서버에서 데이터를 새로 받아와서 사용하는데, 글이 한번 작성되고 수정된 이력이 없는데 매번 서버를 통해 가져다 쓸 필요가 있을까?

ㄴ 자주 업데이트 되지 않는 데이터는 일주일 정도 캐싱 기간을 두고, 그 기간동안에는 캐싱된 데이터를 사용하여 트래픽을 줄일 수 있다.

ㄴ 아니면 수정 액션이 있었을 때 캐싱데이터와 DB데이터 모두 업데이트 해준다.

ㄴ 그리고 캐싱 기능을 사용하면 사용자도 데이터를 빨리 확인할 수 있다. (속도가 빠르다. 서버는 멀리 떨어져 있기 때문이다.)

 

리액트 쿼리의 또하나의 장점: 인터페이스의 표준화

ㄴ 무슨 뜻인가? 로딩중, 성공, 실패 등을 제공해준다.

 

 

- Redux 핵심: 데이터를 컴포넌트 간의 공유하는 것 (공유하기 전에 데이터를 가져와야 하긴 함)

요즘에 Zustand라고 Redux의 작은용량 버전도 나와있다. 아니면 ContextAPI 사용해도 됨.

 

 

React-Query의 상태

- Fresh: 이 데이터는 항상 최신 데이터이고 굳이 업데이트 하지 않아도 된다. 기본적으로 서버에서 데이터를 불러오면 Fresh 상태이다.

그럼 언제까지 Fresh 상태인가? => 그건 우리가 정해줘야 한다.

 

- Fetching: 데이터를 가져오는 중일 때 (이건 너무 빨라서 확인하기 어려움)

 

 

- Stale: 기회가 되면 새로운 데이터로 가져와라.

new QueryClient({

  queries: {

    refetchOnWindowFocus: false, // 다른 탭 갔다가 다시 돌아올 경우 데이터 새로고침해라 (false면 작동안함)

    retryOnMount: true, // 컴포넌트가 리액트에 마운트 된 순간에 데이터 새로고침해라.

    refetchOnReconnect: true, // 인터넷 연결이 끊켰다가 다시 연결되면 데이터 새로고침해라.

 

    retry: false // 데이터 가져오는걸 시도했는데 실패한 경우 다시 시도하는 걸 설정할 수 있음. (false면 다시 시도 안하겠다라는 의미)

  }

})

 

이렇게 전역으로 데이터가 언제 새로고침 되어야 하는지 설정할 수 있고

 

특정 query에서만 하고 싶다면 useQuery안에서 옵션을 주면 된다.

useQuery({

  queryKey: ...,

  queryFn: ...,

  staleTime: 0  // staleTime: fresh -> stale로 변경되는데 걸리는 시간 (ms 단위)

})

 

만약 staleTime: 60 * 1000 으로 설정하면 1분 동안 fresh 상태로 설정할 수 있다.

staleTime: Infinity 도 있는데 이건 항상 fresh하다는 뜻 (한 번 데이터를 가져왔으면 그 뒤로는 계속 캐시해서 가져오겠다)

 

stale 상태에서 fetch를 다시하면 서버에서 데이터 받아온다.

fresh 상태에서 fetch하면 캐시에서 데이터 받아온다.

 

=> 컨텐츠의 속성에 따라 staleTime을 설정해주도록 하자. (한 번 작성되고 수정될 일 없는 경우는 캐시 데이터를 사용하도록 등등..)

 

gcTime: 가비지컬렉터 타임 -> 기본: 5분

 

 

 

staleTime보다 gcTime이 항상 더 길어야 한다. (staleTime < gcTime)

 

만약 staleTime보다 gcTime이 더 짧다면? (staleTime > gcTime 이라면?)

staleTime은 우리가 캐시데이터를 이 시간동안 사용하겠다는 의미인데, gcTime이 끝나면 메모리 정리가 되기 때문에 캐시 데이터도 날라간다. => staleTime이 끝나기 전에 gcTime으로 인해 캐시가 정리되어 버린다! => 우리의 의도와 맞지 않게 돌아감.

 

react-query의 queryKey는 중복되면 안된다. (중복된다는 건 같은 캐싱 데이터를 사용한다는 뜻..)

 

enabled 옵션

ㄴ 특정 상황에서 query를 사용하지 않겠다고 설정할 수 있음.

ㄴ 한 컴포넌트 내에서 게시글 목록을 불러올 때, 유저가 로그인 되었을 때에만 가져오고 싶다면

    enabled: 유저 로그인 === true 이런 식으로 설정하면 된다.

ㄴ 항상 최적화를 생각하자!!!

 

 

 

 React-Query로 인피니트 스크롤링 구현하기

=> prefetchInfiniteQuery로 만들어주면 된다. 대신 initialPageParam, getNextPageParam 넘겨주어야 함!

=> 이렇게 하면 [[1,2,3,4,5], [6,7,8,9,10]] 이렇게 2차원 배열로 결과값이 돌아오기 때문에 이것만 잘 풀어주면 됨.

 

react-intersection-observer로 언제 다음 페이지를 호출하는지 알아내기 (Intersection Observer)

=> 가상의 태그를 페이지 가장 아래에 하나두고

=> 스크롤에 의해 그 태그가 보이는 순간 -> 다음 페이지를 불러온다.

 

useEffect(() => {

  if (inView) {  // react-intersection-observer에서 제공하는 inView

    // react-query가 fetching이 아니고, 다음 페이지가 있을 때 다음 페이지를 불러오도록

    !isFetching && hasNextPage && fetchNextPage(); 

  }

}, [inView, isFetching, hasNextPage, fetchNextPage])

 

 

 

<Suspense> 페이지가 로딩될 때까지 기다린다.

로딩의 의미?

ㄴ 서버 데이터 패치하는 것 까지 기다린다. (awat fetch)

ㄴ 컴포넌트를 lazy loading 해두었을 때

 

loading.tsx, error.tsx를 page.tsx와 같은 레벨에 두고 사용.

 

페이지가 아닌 게시글 목록 같은 데이터에 loading을 보여주고 싶다면? => react-query의 isLoading or isPending을 사용하면 됨.

==> useSuspenseQuery를 사용하면 Suspense의 loading이랑 error를 사용할 수 있다.!! 마찬가지로 useSuspenseInfiniteQuery 사용.

 

Suspense로 명시적으로 사용하면 먼저 그릴 수 있는 부분은 화면에 먼저 렌더링 시키고, loading이 필요한 부분만 로딩바를 적용시킬 수 있다.

 

 

 

 

 

react-query를 프로젝트에서 사용해봐야겠다..!!!

+ Recent posts