nextjs toolkit react-query rtk-query react-hook-form yup

반응형

 

정리해보면

nextjs + react-query + redux-toolkit + rtk-query + react-hook-form + yup

의 구성이 좋다.

SSR 이 아니라면 CRA (create-react-app) 로. SSR 이면 CNA (create-next-app) 로. 물론 모두 typescript 를 적용.

 

React-Query, RTK-Query, SWR 등은 요청 캐싱용 라이브러리이지 리액트에서 말하는 컴포넌트의 상태, 리덕스의 전역 상태와는 관련이 없다. Hook 와 단일자원(웹소켓이라던가 DB 라던가)의 조합은 마치 전역 상태와 같은 늬앙스를 줄 수 있는데 이는 Hook + 단일자원 이 원래 그러한 역할을 할 수 있기 때문이다. 이것이 늬앙스가 비슷하다하여 마치 리덕스 전역 상태를 대체한다던가 하는 생각은 잘못된 것이다. 그냥 요청 캐싱용 라이브러리이고 요청이라는 것은 단일 자원의 성격이라 늬앙스가 그런것이지 그냥 서버요청에 대한 캐싱용 라이브러리이다. 자꾸 리덕스와 SWR 같은 것을 비교하면서 SWR 이 리덕스를 대체할 수 있느냐는 의견을 가지는 경우를 보아서 의견을 적어두었다.

 

https://velog.io/@yrnana/비슷한-라이브러리-비교해보는-글

 

 

Nextjs ( https://nextjs.org/ )

React Server Side Rendering 용 프레임워크.

프론트 서버라는 개념이 추가되며 프론트 서버에서 각 페이지 컴포넌트에서 export 시키는 getServerSideProps, getStaticProps, getStaticPaths 에서 데이터 관련 로직에 따라 초기값을 셋팅하고 header 및 각종 js 등을 모두 적용하여 컴파일하여 브라우저로 내려준다. 내려준 다음부터는 원래의 React 같은 Single Page App 으로 동작한다. 또한 redux 같은 전역 상태를 getServerSideProps, getStaticProps 여기서 사용할 수 있어야 하는데 그것을 위해서 next-redux-wrapper 의 createWrapper 를 통해 전역 redux 상태와 조합된 getServerSideProps, getStaticProps 함수를 가져올 수 있다. export const getStaticProps = wrapper.getStaticProps(async(context) => {}) 와 같이 해서 redux store 와 조합된 getServerSideProps, getStaticProps 를 사용할 수 있게 된다. 그리고 페이지가 브라우저로 내려지면 최초에 redux store 에 getServerSideProps, getStaticProps 에서 dispatch 한 것들을 셋팅해주어야 하는데 HYDRATE 라는 리듀서 액션을 추가하면 그 작업을 해준다. React 의 그리고 nextjs 에서 말하는 hydrate 라는 작업과 HYDRATE 액션 추가는 다른 것이다. 대략적으로 비슷한 의미의 행위이긴하다.

 

getServerSideProps, getStaticProps 안에서 React Component 가 요청을 통해서든 어떤 작업을 통해서든 초기 상태를 셋팅하거나 또는 dispatch 를 통해 redux store 의 초기 상태를 셋팅하여 내려주는 것까지가 nextjs SSR 의 기능이다. getInitialProps 는 차후 deprecated 될 것이라 한다.

 

* 약간 혼동될 수 있는 부분이 page1 > page2 로 페이지 이동하는 부분이다. CSR (Client Side Rendering, 즉 SSR 이 아닌 일반적인 React) 의 경우 historyAPI 로 이동하므로 리프레쉬가 되지 않는다. 그래서 redux store 가 유지된다. nextjs 를 사용하면 page1 > page2 로의 페이지 이동에서 리프레쉬 되어서 redux store 가 리셋되지 않을까? 라고 의문을 가질 수 있지만 아니다. 최초 page1 을 가져오면 그 다음부터는 page2 로 이동하는 것은 동일하게 historyAPI 로 동작한다. 또한 page1 을 로드할 때도 최초 초기 데이터 셋팅하고 초기 페이지만 빠르게 컴파일된 상태로 로드할 뿐이고 page2 로 이동해도 그다음부터는 리프레쉬가 아니라 코드스플릿팅 처럼 동적으로 페이지를 가져온다. 즉 페이지컴파일, 캐싱, 하이드레이팅 의 과정이 이루어지면서 SEO 에 강한 빠른 페이지 로딩이 가능한 것.

 

https://stackoverflow.com/questions/64805494/how-to-properly-hydrate-redux-state-in-nextjs-on-page-refresh

 

페이지 리프레쉬를 해도 로그인 정보와 같은 것을 계속 기억된 상태로 공유하기 위해서는 redux-persist 같은 것을 사용하거나 쿠키나 로컬스토리지를 통해 유지하는 방법을 사용해야 한다. 그런데 위 링크에서 제시된 이슈와 같이 redux-persist 를 사용할 경우 PersistGate 프로바이더로 감싸게 되고 이럴 경우 브라우저의 persisted 데이터를 가져오기 전까지 UI 를 막기 때문에 SSR 의 목적인 미리 컴파일된 페이지의 빠른 렌더링의 기능을 잃어버린다고 한다. 그래서 next-redux-persist 라는 것을 사용하면 _app.ts 에서 App.getInitialProps 를 넣어주어서 각각의 페이지가 로드될 때 호출되도록 하여 해결할 수 있었다고 한다. 하지만 이럴 경우 모든 페이지가 SSR 되어 모든 페이지에서 nextjs 의 static page optimization 을 사용할 수 없게 되었다고 한다. 그래서 추천하기로는 redux-persist 나 next-redux-persist 같은 걸 사용하지 말고 로컬스토리지나 쿠키같은 걸 가져오는 로직은 useEffect 안에서 넣어서 SSR 과는 무관하게 브라우저에 페이지 로드 된 후에 가져오도록 분리하라고 한다. 즉, 위에서 언급했듯 nextjs 의 역할은 초기 데이터 넣고 페이지를 만들어 내려주며 정적일 경우 페이지 캐싱도 할 수 있도록 하는 것. 브라우저 측의 데이터를 가져온다던가 하는 것은 useEffect 쪽에 넣어서 분리하는 것이 좋다. 

그리고  redux-persist 를 만약에 사용하려면 그냥 store 를 redux-persist 적용한 채로 리턴하면 안되고 브라우저 측의 store 에만 적용되어야 하므로 https://www.robinwieruch.de/redux-persist-next-js 이런식으로 고려도 해야 한다. 하지만 이렇게 하여도 위의 이슈 처럼 PersistGate 가 로컬스토리지나 쿠키 쪽에서 데이터를 다 가져오기 전까지 UI 가 표시되지 않는 것을 막을 수는 없다. PersistGate 로 감싸져 있는 형태이기 때문에 아예 초기 렌더링 조차 되지 않는 것인데 이것이 의도된 것일 수도 있으므로 그리고 로컬스토리지나 쿠키에서 데이터 가져오는 것이 그렇게 사용자 사용성을 떨어뜨릴 것 같지 않으므로 이렇게 그냥 사용하는 것이 좋아보인다. 그럼에도 민감하다면 PersistGate 로 감싸는 것을 하지 말고 따로 useEffect 에서 로드해주는 방식을 강구해보면 될 것이다. 그럴 경우 초기에 화면은 보여지고 로컬스토리지나 쿠키의 데이터를 가져오는식이 될 것이다. 그냥 PersistGate 를 사용하는 것이 좋아보인다. 애초에 로컬스토리지나 쿠키의 데이터를 가져오기 전까지는 화면 안보여주는 것이 맞는 것인 듯 하다. 특이한 상황에서 다른 방법도 강구해보는 것이 좋을 것 같다.

https://github.com/vvo/next-iron-session/blob/master/examples/next-typescript/lib/session.ts 세션 적용 인증 관련해서 Server Side 처리 vercel 측의 공식 문서임. 이런 방식은 좀 복잡해보이고 번거로워 보인다... redux-persist 사용하는게 편한데....

 

만약에 블로그 같은식의 웹앱을 만들 계획이라면 gatsby 를 사용하는 것도 좋아보인다. (https://www.gatsbyjs.com/)

https://blog.banksalad.com/tech/build-a-website-with-gatsby/

 

https://www.merixstudio.com/blog/introduction-using-redux-toolkit-nextjs-and-typescript/ << 이건 그냥 CSR 까지만 셋팅. 그냥 참고용

https://velog.io/@danmin20/Next.js-Typescript-Styled-component-%EC%89%BD%EA%B2%8C-%EA%B5%AC%EC%B6%95%ED%95%98%EA%B8%B0  << 좋아보임.

https://velog.io/@danmin20/Next.js%EC%97%90%EC%84%9C-redux-toolkit-%EC%84%B8%ED%8C%85%ED%95%98%EA%B8%B0  << 좋아보임.

https://xploitdev.com/dev/next-redux-toolkit/

https://cotak.tistory.com/164

https://kyounghwan01.github.io/blog/React/next/getInitialProps/#getinitialprops-%E1%84%8B%E1%85%B5%E1%84%8C%E1%85%A5%E1%86%B7

https://min9nim.github.io/2018/11/nextjs-getInitialProps/

https://helloinyong.tistory.com/315

https://fourwingsy.medium.com/next-js-hydration-스타일-이슈-피해가기-988ce0d939e7

 

 

React-Query 나 RTK-Query 는 모두 요청 캐싱용 라이브러리이다. React-Query 는 component 단위의 요청용으로 (리액트 컴포넌트에서 바로 요청하는 경우) 로 사용하기 좋으며 RTK-Query 는 redux-toolkit 과 함께 전역 상태인 리덕스의 요청용으로 사용하기 좋다.

 

백엔드와 프론트가 서로 요청을 통해 데이터를 주고 받을 때 프론트측의 DB 구조도 고려하여 normalization 을 신경써야 한다. 그리고 그것은 React Component 레벨에서 바로 요청을 하는 경우와 Redux 와 같은 전역 상태 레벨에서 요청하는 경우로 나눌 수 있다. 두 경우 모두 normalization 은 해주는 방향이어야 하지만 전역 상태 레벨에서는 toolkit 을 사용할 경우 nomalizr 를 통한 normalization 을 거의 필수적으로 하면서 요청과 상태 모두 전역에서 수행됨을 염두에 두어야 한다. React Component 레벨에서 바로 요청하는 경우에는 조금은 rough 하게 다루어도 좋고 nested 된 데이터 형태를 피하긴 해야하지만 경우에 따라서 조금은 유도리 있게 하여도 된다. 이렇게 React Component 레벨에서 요청할 경우에도 캐싱 라이브러리를 사용하면 좋은데 이때는 React-Query 를 사용하면 좋다. 전역 레벨의 경우 redux-toolkit 을 대부분 사용하기에 RTK-Query 를 사용하면 좋다.

 

결국 요청 캐싱의 경우 과거에는 직접 구현하는 고난이도 기법이었지만 최근에 이러한 기법들이 정리가 잘 되어서 라이브러리를 가져다 사용하면 된다. 또한 RTK-Query 의 경우 redux-toolkit 의 thunk 부분을 작성할 때 각 요청마다 반복적으로 만들어야 하는 responseData, isLoading, error 같은 것을 줄여줄 수 있는 기능도 한다.

 

React-Query ( https://react-query.tanstack.com/examples/simple )

요청 캐싱용 라이브러리

https://velog.io/@elin_me/React-Query-도입기

https://maxkim-j.github.io/posts/react-query-preview

https://velog.io/@kimbiyam/React-Query

https://merrily-code.tistory.com/76

https://blog.rhostem.com/posts/2021-02-01T00:00:00.000Z

https://swoo1226.tistory.com/216

 

 

RTK-Query ( https://redux-toolkit.js.org/rtk-query/overview )

요청 캐싱용 라이브러리. redux-toolkit 과 조합이 좋아서 toolkit 과 함께 전역 상태용 Thunk 미들웨어 대신의 요청 캐싱용 라이브러리로 사용할 수 있다. Thunk 처럼 미들웨어와 같이 toolkit 과 자연스레 조합이 되며 thunk 요청의 경우 response data, isLoading, error 와 같이 각각 상태값을 매번 만들어주어야 하는 것에 대한 작업을 간단하게 해주면서 또한 캐싱 기능도 제공하기 때문에 리덕스와 같은 전역 상태용 요청 미들웨어 라이브러리로 사용하면 매우 좋다.

https://velog.io/@jungsangu/RTK-Query-%EA%B3%B5%EC%8B%9D-%EB%AC%B8%EC%84%9C-%ED%95%9C%EA%B8%80-%EB%B2%88%EC%97%AD

https://velog.io/@jungsangu/RTK-Query-%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0

https://velog.io/@jungsangu/RTK-Query-%EA%B0%9C%EC%9A%94

https://velog.io/@jungsangu/RTK-Query-%EB%8B%A4%EB%A5%B8-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC%EB%93%A4%EA%B3%BC-%EB%B9%84%EA%B5%90

 

 

 

React 18 Suspense

https://velog.io/@0307kwon/사용자-경험-개선-1편-react-suspense

https://develment.blog/react-suspense%EB%A1%9C-%EB%B9%84%EB%8F%99%EA%B8%B0-fetch-%EA%B4%80%EB%A6%AC

 

 

 

 

반응형

댓글

Designed by JB FACTORY