티스토리 뷰
생활코딩 이고잉님의 유투브 `React 서버 통신에 회의가 든다면 - RTK Query`를 기반으로 작성하였습니다.
Server Hook 사용법
./app/api 의 api 객체를 이용하기
RTK Query로 서버와 통신
읽기: useGetCountQuery ({name})
쓰기: userSetCountMutation()
-첫번째 원소 함수({name, value}) 로 데이터 전송
RTK Query의 특징
1️⃣ use-Query는 읽기 전용(read-only)
- 객체를 리턴 // {}
- data, isFetching, isLoading 중요
- isLoading은 state가 초기화되기 전(undefined)일때 첫번째 로딩시
- isFetching은 loading시마다 실행
- 자동실행
2️⃣ use-Mutation은 쓰기 전용
- 배열을 리턴 // []
- 첫번째 원소 함수로 수동실행
- 첫번째 원소 함수는 promise로 응답 값 전달(서버에 요청한 응답값을 바로 받아서 즉시 사용할 수 있음 async-await을 같이 활용)
- 추가 설명: 첫번째 원소인 함수는 promise를 리턴한다. => 즉 이 함수를 async await으로 감싸고 변수에 결과값을 담아주면 바로 확인해 볼 수 있다.
- 두번째 원소 객체의 isLoading
- useMutation은 isFetching이 따로 없이 isLoading만 존재 => 서버와 데이터를 통신할 때마다 isLoading가 true값으로 바뀐다.
서버 캐시
클라이언트에서 임시로 가지고 있는 서버의 데이터(언제든지 변할 수 있는)
각각의 컴포넌트가 구독하고 있는 전역 저장소의 서버 데이터 정도로 이해했다. 클라이언트 상태관리 라이브러리와 다른 점이라고 하면 `태그`라는 개념을 사용하여 이 `태그`를 기준으로 최신값을 서버에서 가져와 업데이트할 수 있다.
- redux devtools로 확인가능하다. 하단에 RTK Query를 클릭하면 된다.
RTK Query는 Redux와 같이 사용할 수도 있고 단독으로 사용하는 것도 가능하다.
RTK Query (without Redux)
src>app>api.js
*참고로 redux toolkit에서 권장하는 폴더 구조가 있는 거 같습니다. 확인 필요
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
// /count의 GET / POST / PATCH / DELETE 등 operation하나를 endpoint라고 한다.
// createApi함수는 각각의 엔드포인트(에시에서 getCount)를 자동으로 갱신할 수 있는 hook을 생성해준다. e.g. useGetCountQuery
export const api = createApi({
baseQuery: fetchBaseQuery({ baseUrl: "https://example.com/api" }),
//tagTypes: 전역적으로 사용하고 있는 태그 이름 지정
tagTypes: ["Count"],
endpoints: (builder) => ({
getCount: builder.query({
query: ({ name }) => `count/${name}`,
// 서버 캐시를 컴포넌트가 구독하고 있는데 이 캐시가 비게되면 서버에서 자동으로 새 값을 넣어준다.
// result는 서버 데이터값, error는 에러났을 때 내용, arg는 useGetCountQuery({name})에서 name이 arg로 들어간다.
providesTags: (result, error, arg) => [
{ type: "Count", id: arg.name },
],
}),
setCount: builder.mutation({
//뮤테이션의 경우는 쿼리의 프로퍼티로 함수를 지정해주면 된다.
//뮤테이션 훅이 반환하는 배열의 첫번째 원소인 함수로 전달받는 인자가 query 함수의 매개변수로 자동으로 들어오게 된다.
//query에는 서버와 통신하는 정책을 명시해주는 곳이라고 생각하면 된다.
query: ({ name, value }) => {
return {
url: `count/${name}`,
method: "POST",
body: { value },
};
},
//서버 캐시를 무효화만들어서 지워버린다 라는 의미,
//이 아래의 태그에 해당하는 서버 캐시를 지워버린다는 의미 => 서버 캐시가 지워졌으니 새로운 값을 서버에서 update하겠죠?
invalidatesTags: (result, error, arg) => [
{ type: "Count", id: arg.name },
],
}),
}),
});
- 여기서 만든 api를 index.jsx에서 주입해줘야한다. (vite에서는 main.jsx)
src>main.jsx(index.jsx와 같습니다. vite를 사용하고 있어 이름이 다름!)
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.jsx";
import "./index.css";
import { ApiProvider } from "@reduxjs/toolkit/dist/query/react";
import { api } from "./app/api.js";
ReactDOM.createRoot(document.getElementById("root")).render(
<React.StrictMode>
<ApiProvider api={api}>
<App />
</ApiProvider>
</React.StrictMode>
);
- ApiProvider 컴포넌트를 임포트해오고 위에서 만들어 놓은 api를 프롭으로 넘겨준다.
- 끝 ㅎ
RTK Query (with Redux)
createApi로 만든 api를 store에 등록해줘야 한다. 이때, api에 추가되는 것이 있는데 바로 reducerPath이다.
- reducerPath의 값은 state의 이름이라고 생각하면 된다.
src>app>api.js
export const api = createApi({
reducerPath: "countApi", // 기본적으로 정하지 않으면 api로 된다.
baseQuery: fetchBaseQuery({ baseUrl: "https://example.com/api" }),
//tagTypes: 전역적으로 사용하고 있는 태그 이름 지정
tagTypes: ["Count"],
// (코드 중략)
store를 만들어놓지 않았으니 store를 만들어준다.
src>app>store.js
import { configureStore } from "@reduxjs/toolkit";
import { api } from "./api";
//스토어에 리듀서를 등록해주고, 미들웨어도 등록(이 로직은 저도 잘 모름)
export const store = configureStore({
reducer: {
//api state이름과 api로 자동생성된 리듀서 함수도 등록
[api.reducerPath]: api.reducer,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(api.middleware)
});
다시 index.jsx(vite: main.jsx)로 돌아와 만들어놓은 store를 주입해준다.
기존 리덕스처럼 Provider컴포넌트에 store를 주입해주면 된다.
src>main.jsx
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.jsx";
import "./index.css";
import { Provider } from "react-redux";
import { store } from "./app/store.js";
ReactDOM.createRoot(document.getElementById("root")).render(
<React.StrictMode>
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>
);
'Frontend > react.js' 카테고리의 다른 글
[React] Suspense 와 React.lazy (0) | 2023.05.28 |
---|---|
[SWR | 서버데이터관리] SWR 사용해보기, optimistic vs pessimistic UI, cookie 공유 tip (0) | 2023.05.24 |
[RTK Query | Redux] RTK Query란? (redux, redux-toolkit 비교) (0) | 2023.05.11 |
[React | vite] 번들 사이즈 비주얼라이저(애널라이저) (0) | 2023.04.20 |
[React | CSS] #root 과 :root의 차이점 (전역 CSS) (0) | 2023.04.19 |
- Total
- Today
- Yesterday
- 타입스크립트 DT
- 원티드 프리온보딩 FE 챌린지
- reactAPI
- nvm경로 오류
- ~ ^
- nvm 설치순서
- && 셸 명령어
- grid flex
- 프리온보딩 프론트엔드 챌린지 3월
- 원티드 3월 프론트엔드 챌린지
- 프리렌더링확인법
- getStaticPaths
- 원티드 FE 프리온보딩 챌린지
- getServerSideProps
- fs모듈 넥스트
- 항해99추천비추천
- text input pattern
- Prittier
- tilde caret
- 타입스크립트 장점
- 형제 요소 선택자
- D 플래그
- 항해99프론트
- aspect-ratio
- is()
- 원티드 프리온보딩 프론트엔드 챌린지 3일차
- float 레이아웃
- 항해99프론트후기
- 부트캠프항해
- 틸드와 캐럿
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 | 29 |
30 | 31 |