컴포넌트 간에 이동되는 props
와 달리 컴포넌트 내부에서 관리되는 자바스크립트 객체
서로 다른 컴포넌트에서 동일한 데이터를 다룰 땐, 해당 데이터의 출처가 동일해야 한다. 그래야 서로의 변화에 동적으로 반응할 수 있기 때문이다. 즉 상태의 일관성 (데이터의 무결성
)을 잘 지켜야한다.
Single Source of Truth
이라는 방법론이 이러한 상태의 일관성을 유지하기 위해 등장한 방법론인데, 말그대로 신뢰할 수 있는 단일 출처를 말한다.
이 방법론이 React가 택한 방법론이다. 따라서 우리는 React에서 데이터의 무결성, 즉 서로 다른 컴포넌트에 분포되어있는 공통된 출처의 데이터의 일관성을 유지할 수 있도록 상태 관리를 해주어야 한다.
Client State | Server State | |
---|---|---|
위치 | 클라이언트에 저장된 데이터 | 서버나 외부 데이터 소스에 저장된 데이터 |
접근성 | 클라이언트만 접근 가능 | 접근 권한이 있는 모든 클라이언트 접근 가능 |
데이터 관리 | 클라이언트에서 관리 (Redux, Recoil 등 상태관리 라이브러리 사용) | 서버에서 관리 (데이터베이스 사용) |
지속성 | 세션 간에 필연적으로 지속되진 않음 | 일반적으로 세션 간에 지속성 유지 |
네트워크 요청 | 데이터를 가져오거나 업데이트하려면 네트워크 요청이 필요할 수 있음 | 데이터 접근 또는 업데이트를 위해 네트워크 요청이 필요할 수 있음 |
보안 | 클라이언트가 액세스할 수 있고 보안 수준이 낮음 | 인증 및 암호화로 보호할 수 있으므로 더 안전 |
성능 | server state에 비해 속도 빠름 | client state에 비해 속도 느림 |
확장성 | 클라이언트 기기 용량이 제한적이어서 확장성이 다소 떨어짐 | 전용 서버나 데이터 소스로 관리되기 때문에 용량이 커서 확장성이 비교적 높음 |
예시 | 컴포넌트 state, Redux state, 브라우저 쿠키 | DB 레코드, API 응답, 서버 세션 데이터 |
본 아티클에서는 Server State 라이브러리의 대표 React Query와, Client State 라이브러리의 대표 Recoil을 알아보고자 한다.
React에서 데이터 fetching
과 캐싱 프로세스
를 간소화해주는 라이브러리
Client에서 API와 통신을 하기 위해서는
추가적으로 useEffect, useState를 함께 쓰면서 데이터를 fetching 해왔다.
하지만 React Query를 사용하면 이러한 Hook들의 필요성이 사라진다.
Query
Mutation
Query Caching
Query Invalidation
데이터 Fetching 용
API 엔드포인트나 DB에서 데이터를 비동기적으로 가져오도록 서버에 요청하는 것
const query = useQuery( { queryKey: [ ‘key’ ], queryFn: callback })
queryKey
queryFn
// 예시
const getProducts = () => fetch( 'https://jsonplaceholder.typicode.com/users')
.then( res => res.json() )
const query = useQuery( { queryKey: [‘users’], queryFn: getTodos })
반환값
쿼리의 상태 정보를 담고 있는 객체
const { isLoading, isError, data, error, refetch, remove } = useQuery( { queryKey: [‘todos’], queryFn: getTodos });
대표적인 프로퍼티
isLoading
쿼리가 현재 로딩 중인지 여부 (boolean)isError
쿼리 결과가 오류인지 여부 (boolean)data
쿼리를 통해 성공적으로 fetching된 데이터error
쿼리 실행 중 발생한 모든 에러refetch
쿼리 데이터를 수동으로 refetch 하는 트리거 메소드remove
캐시에서 특정 쿼리 제거하는 메소드useQuery
는 기본적으로
[ useQuery 옵션 ]
옵션 | 역할 | 기본값 |
---|---|---|
refetchOnWindowFocus | 데이터가 오래된(stale) 경우 브라우저 창이 포커스 되면 리페치 | true |
refetchOnMount | 데이터가 오래된 경우 마운트 시 리페치 | true |
refetchOnReconnect | 데이터가 오래된 경우 재연결 시 리페치 | true |
하지만 브라우저가 idle 상태를 유지할 때엔, 데이터 업데이트를 감지하여 자동으로 리페치해주지 않는다.
이를 보완하기 위해서 refetchIntervel
옵션을 사용할 수 있다.
API 엔드포인트나 DB에 데이터를 새로 생성, 수정, 삭제
const mutation = useMutation({ mutationFn: mutationFunction });
mutationFn
// 예시
const AddUser = useMutation({
mutationFn: ( user ) => {
return fetch('https://jsonplaceholder.typicode.com/users',
{
method:'post',
headers: {
"Content-Type": "application/json",
},
body:JSON.stringify( user )
}).then( res => res.json() )
})
반환값
뮤테이션 실행 결과와 관련된 정보를 담은 객체
대표적인 프로퍼티
isLoading
뮤테이션이 현재 로딩 중인지 여부 (boolean)isSuccess
뮤테이션 결과가 성공인지 여부 (boolean)isError
뮤테이션 결과가 오류인지 여부 (boolean)data
뮤테이션 실행 후 반환된 데이터 (있을 때만)mutate
해당 뮤테이션 실행을 위해 호출할 메소드. (인자에 담을 변수를 객체로 전달)reset
뮤테이션 초기 상태로 리셋하는 메소드onSuccess
뮤테이션 성공시 호출할 콜백함수onError
뮤테이션 실패시 호출할 콜백함수원격 서버와 통신하는데에 걸리는 시간을 단축하고자,
여러번 불러올 데이터는 캐시에 저장하여 반복해서 필요로 할 경우 원격 서버가 아닌 캐시에서 빠르게 가져올 수 있는 방식
useQuery 훅 사용 시, 지정했던 고유 키
밑에 반환된 데이터가 캐싱된다.
기본적으로는 캐시 데이터는 오래된(stale) 상태로 기록된다.
[ Query Caching과 관련된 useQuery 옵션 ]
const query = useQuery({
queryKey: [‘users’],
queryFn: getUsers,
staleTime: 5000,
cacheTime: 60000
})
staleTime
cacheTime
지정해준 staleTime
과 무관하게 즉시 데이터를 stale 상태로 처리해야하는 경우가 있다.
예를 들어, API에 POST 요청을 보내 데이터 값을 업데이트할 때엔, API 엔드포인트에 있는 데이터의 값이 캐시에 저장되어있는 값보다 더 최신 상태가 되고, 캐시에 저장되어있는 데이터는 곧바로 outdated한 값이 되어버린다. 이럴 때엔 즉시 캐시 데이터를 stale 상태로 처리해줘야 한다.
React Query의
QueryClient
객체의invalidateQueries
메소드 활용
useQueryClient
훅을 통해 queryClient 객체 생성invalidateQueries
활용하기import { useQueryClient } from "@tanstack/react-query";
// useQueryClient 훅을 사용하여 queryClient 객체 생성
const queryClient = useQueryClient();
// 캐시의 모든 쿼리 무효화
queryClient.invalidateQueries();
// 'users'로 시작하는 키가 있는 모든 쿼리 무효화
queryClient.invalidateQueries({ queryKey: ["users"] });
→ 코드 간소화 & 성능 최적화
React Query는 강력한 Server State 관리 라이브러리이다!
😭 조심스레 한계점을 먼저 알아보고 가자
위 사진은 내장 API인 Context API를 제외한 대표적인 Client State 관리 라이브러리들의 npm 설치 수 비교 그래프이다. (근 1년 기준)
한눈에 알 수 있듯이 Recoil보다 Redux가 설치 수에 있어 훨씬 더 우세하다는 것을 확인할 수 있다.
이 그림에서 그 한계점을 바로 확인할 수 있는데, 바로 최신 라이브러리인 만큼 개발자 커뮤니티가 매우 빈약하기 때문에 어떠한 이슈가 발생하여도 집단지성의 힘을 빌려 해결하기 어려운 상황이 발생할 수 있으며, API 혹은 공식문서에 대한 신뢰도도 비교적 낮다고 할 수 있다.
그러나!
위와 같은 면에서는 뚜렷한 강점을 가지고 있기 때문에 React 라이브러리를 사용하는 프론트엔드 개발자라면 충분히 적극적으로 활용해보면 좋을 라이브러리라고 생각한다.
atom
: 상태의 단위
selector
: atom의 상태 값을 동기/비동기 방식으로 업데이트
const mySelector = selector({
key: 'MySelector',
get: ({get}) => get(myAtom) * 100,
});
get
: 콜백함수의 인자에 담겨있는 get
함수를 통해 다른 atom/selector를 구독할 수 있다.
위의 예시를 기반으로 atom과 selector의 작동방식을 설명하자면,
myAtom
이라는 별도의 atom에서 파생된 데이터를 관리하고자 mySelector
라는 selector를 생성한 것이고,
mySelector
가 하는 일은 myAtom
상태의 값을 읽어와 100을 곱해준 뒤 반환하는 함수이다.
이 때, mySelector
셀렉터는 myAtom
아톰에 대해 종속된다/의존한다/구독한다 라고 할 수 있으며,
이럴 경우 myAtom
의 값이 업데이트될 때마다 mySelector
도 재실행되게 되어 동적으로 값을 관리할 수 있게 된다.
selector에 get 함수만 정의될 경우,
RecoilValueReadOnly
객체를 반환하여, 함수 반환 값을 읽는 것만 가능해진다.
반면, 쓰는 것도 가능한 selector의 set함수도 있으나, 본 아티클의 주제에 직결되는 내용만 다루기 위해 생략한다. 관련 내용은 문서에서 참고하자!
useState와 매우 유사한 형태이므로, 쉽게 사용할 수 있다.
useRecoilState
: state 값과 setState 모두 사용할 때 const [변수명, setter명] = useRecoilState(atom명);
useRecoilValue
: state 값만 사용할 때 const 변수명 = useRecoilValue(atom명);
useSetRecoilState
: setState만 사용할 때 const setter명 = useSetRecoilState(atom명);
ReactDOM.createRoot(document.getElementById("root")!).render(
<>
<RecoilRoot>
<ThemeProvider theme={theme}>
<GlobalStyle />
<App />
</ThemeProvider>
</RecoilRoot>
</>
);
Recoil을 사용하고자 하는 컴포넌트의 상위에서 RecoilRoot
를 import 해와서 감싸준다.
일반적인 경우, Recoil을 전역적으로 사용하기 때문에 App.tsx / main.tsx 에서 사용한다.
atom.ts
파일을 생성하여 원하는 atom을 생성한다.
// recoil/atom.ts
export const followState: RecoilState<boolean> = atom({
key: "followState",
default: false,
});
key
: 모든 atom은 반드시 전역적으로 고유한 key를 가진다. const follow = useRecoilValue(followState);
const setFollow = useSetRecoilState(followState);
Recoil은 강력한 Client State 관리 라이브러리이다!
지금까지 Client State를 관리할 수 있는 Recoil에 대해 알아보았다.
그렇다면 Recoil은 Server State Fetching과는 전혀 무관한 라이브러리일까?
아니다. Recoil을 사용하여 비동기적으로 데이터를 처리하는 것도 가능한데, 지금부터 그 방법인 Recoil Asynchronous Data Query 에 대해 알아보자.
위에서 본 selector의 get은 값
을 반환해주는 콜백함수를 가졌었다.
그러나 get 함수는 일반적인 값 뿐만 아니라 Promise 객체를 리턴해줄 수 있다.
대표적인 예시로, Server State를 불러오는 Data Fetching의 경우를 보자.
기존에 우리가 async await 를 사용하여 Data Fetching을 해온 방식은 아래와 같다.
const getContent = async () => {
const response = await axios.get(url);
return response.data;
};
// try catch 등은 생략한 가장 기본적인 코드이다
이렇게 비동기적인 API 호출을 실행하여 Promise를 반환하는 함수를 selector의 get으로 넣어보자.
const contentQuery = selector({
key: 'contentQuery',
get: async ({get}) => {
const response = await axios.get(url);
return response.data;
},
});
이제 응답받은 데이터를 사용하고 싶을 땐 selector의 값을 가져오는 Hook이었던 useRecoilValue를 똑같이 사용하면 된다.
const 호출컴포넌트 = () => {
const content = useRecoilValue(contentQuery);
return (<div>{content}</div>);
}
그런데, 만약 Promise가 pending 상태일때, 즉 resolve가 호출되기 전에는 호출컴포넌트
는 무엇을 렌더링해야 할까?
이러한 경우를 처리할 수 있는 것이 바로 React의 Suspense이다.
return (
<RecoilRoot>
<React.Suspense fallback={<div>Loading...</div>}>
<호출컴포넌트명 />
</React.Suspense>
</RecoilRoot>
);
위와 같이 fallback에 Pending 시 렌더링할 콘텐츠를 담은 React.Suspense
로 비동기 selector를 호출하는 컴포넌트를 감싸주면 된다.
그렇다면 만약 Promise의 실행 결과, resolve가 아닌 reject가 호출되어 에러가 발생했을 경우엔 어떻게 처리해주어야 할까?
이러한 경우엔 React의 ErrorBoundary를 활용해줄 수 있다.
return (
<RecoilRoot>
<ErrorBoundary>
<React.Suspense fallback={<div>Loading...</div>}>
<호출컴포넌트명 />
</React.Suspense>
</ErrorBoundary>
</RecoilRoot>
);
위와 같이 <ErrorBoundary>
태그로 비동기 selector를 호출하는 컴포넌트를 감싸주면 된다.
이렇게 Recoil은 React의 Suspense와 ErrorBoundary를 활용할 수 있도록 설계되어있기 때문에 React와의 호환성 및 활용성이 우수한 라이브러리라고 할 수 있다.
Recoil로도 쉽게 Server State를 관리해줄 수 있다!
React Query 진짜,,,, 은근 까다롭고 애증(?)의 관계인데 이렇게 잘 정리해주셔서 감사해요! 만약 data 패칭 시에, useMutation을 사용해 데이터를 생성, 삭제, 업뎃 등의 변화를 주면 그 변화와 동시에 데이터 변화를 클라 화면에서 보여주어야 할 때 queryClient.invalidateQueries
를 사용할 수 있더라구요!
저는 앱잼에서 react query를 처음 사용해 보았는데,
대체로 당시에 찾아보면 react query를 사용함에도 불구하고, useEffect, useState와 같은 훅을 사용하여 데이터 패칭을 하는 경우를 살펴 볼 수 있었습니다. (구글링할 때 예시 코드)
그런데, 이러한 훅의 도움을 받지 않고 사용하려고 하는게 react query라서요!
그래서 react query를 사용해서 data fetching을 할 때 커스텀 훅을 이용하는 방법을 앱잼에서 사용해 봤는데, 저는 꽤 좋았던 것 같습니다!
Query Invalidation에도 인자로 조건을 넘겨줄 수 있는데, 구체적인 키를 전달해서 특정 변수가 있는 쿼리를 무효화할 수도 있고,
queryClient.invalidateQueries({
queryKey: ['todos', { type: 'done' },
})
//무효화o
queryClient.infalidateQueries({
queryKey: ['todos', {type: done'}],
queryFn: fetchTodoList,
}
//무효화x
const todoListQuery = useQuery({
queryKey: ['todos'],
queryFn: fetchTodoList,
})
변수나 하위 키가 없는 쿼리만 무효화하려는 경우에는 exact:true
옵션을 메소드에 전달해서 각 쿼리를 구분해서 무효화할 수도 있습니다. 만약 상단에 exact:true
를 옵션으로 넣어준다면, 상단 예시에서의 무효화 결과는 반대가 될 거라고 하네요!
또, predicate
함수를 전달하면, 해당 쿼리를 무효화할 지 여부에 대한 boolean값을 반환한다고 합니다.
queryClient.invalidateQueries({
predicate: query =>
query.queryKey[0] === 'todos' && query.queryKey[1]?.version >= 10,
})
위와 같은 경우에는 version이 10이상일 경우에만 무효화를 시킬 수 있습니다.
꽤 재미있는 옵션들 같아서 공유하고자 합니다! predicate는 저도 이번에 첨 알았네용,,,
그리고 recoil 맨날 atom만 주구장창^^ 사용했지 selector나 recoil로 비동기처리를 할 수 있는 건 경험해볼 기회가 없었는데,,, 너무 주옥같은 글이었습니다! 감사해요!
저는 전역 상태관리 라이브러리를 아직 사용해본 적이 없는데 이 글을 보고 전역상태 관리 라이브러리에 대한 개념을 이해했어요!! 구독이라는 개념이 뭔가 신선하게 다가오네요!
useQuery
의 stale
이라는 개념을 보면서 동작원리에 대해 찾아보았는데요, 현 시점부터 stale 상태가 될 때까지 남은 시간을 계산하여 timeout에 저장하고 setTimeout을 이용해 timeoutms 만큼의 시간이 지난 후에 currentResult가 stale 상태가 아니라면, fresh에서 stale로 상태를 바꿔주는 updateResult()를 호출하고 이를 통해 fresh 상태에서 설정한 staleTimems 만큼의 시간이 지나면 stale 상태로 바뀌게 된다고 합니다. 상상했던 방식으로 작동한다는 것을 알 수 있었습니다~!!
아 그리구 주의할 점은 stale 상태가 되었다고 해서 refetching이 곧바로 일어나는 것이 아니라, stale 상태가 되고 특정조건을 만족해야 refetching이 일어난다고 합니다!
오홍 리액트 쿼리가 server State 라이브러리의 대표!! 라는 점 처음 알게 되었습니다. 굉장히 유익한 아티클 감사합니다..특히 앞에 state 개념도 상기시켜주셔서 더더욱 더 짚고 가는 느낌으로 좋았어요!
게다가 저는 react 하면 useState, useEffect를 거의 한몸으로 알고 있었는데 리액트 쿼리를 사용하면 이런 hook들의 필요성이 사라지다니!! 굉장히 흥미로웠습니다. 그래서 추가적으로 찾아보니
리액트 쿼리를 사용하면 useEffect나 useState가 필요한 상황이 줄어들 수 있지만, 이 라이브러리가 완전히 이들을 대체하는 것은 아닙니다. 리액트 쿼리는 특정 상황에서 훨씬 편리하게 데이터를 다룰 수 있게 도와주지만, 여전히 useEffect와 useState는 특별한 경우에 필요할 수 있습니다.
아하 그래서 특정 로컬 상태를 관리해야 하는 경우나 데이터를 가져오는 방식을 더 세밀하게 제어해야 하는 경우 등이 그런 상황에 해당합니다. 따라서 리액트 쿼리를 사용할 때에도 프로젝트의 특정 요구사항을 고려하여 결정하는 것이 중요하다는 생각이 듭니당!!
또한 recoil이 server state fetching과 전혀 무관하지 않은것도 아니다면서 이제 Recoil Asynchronous Data Query 를 알려주셨는데 이 부분도 굉장히 유익했습니다.
저 분명 React Query랑 Recoli을 이 글을 통해서 처음 접해보았는데요.. 글을 다 읽고 나니까 약간 마스터한 기분이 들어요ㅎㅎ 글 대로만 한다면 완벽하게 해낼 수 있을 것만 같은 느낌이랄까요..? 그만큼 진짜 술술 읽히고 글의 흐름을 따라가니까 이해하기 쉬웠던거 같아요!
React Query에서는 서버상태 관리에 도움이 되는 다양한 도구들도 지원한다고 하는데요. 몇가지 말해보자면 사용자를 위해 데이터의 페이지네이션 혹은 무한스크롤의 상황에서 필요한 경우, 데이터를 가져올 수 있도록 하는 Lazy Loading 도구를 지원한다고 합니다! 또한 각 쿼리들은 key로 식별되기 때문에 페이지 내 여러 컴포넌트가 동일한 데이터를 요쳥하는 경우, 한번만 요청하도록 중복을 제거할 수도 있다고 합니다. Query Caching과는 조금 다른 느낌인거 같기도 하네요.. React Query의 다양한 기능을 활용해볼 수 있도록 좀 더 공부를 해보고 싶어졌어요!
제 React Query와 Recoil의 첫 시작을 도와준 너무나도 유익한 아티클 감사드려요♡
아티클 처음부터 state의 개념이 무엇인지 client state와 server state의 개념으로 나누어서 설명해주셔서 state의 개념에 대해 더욱 확실히 알 수 있어서 너무 좋았어요!!!
저는 이번 아티클에 언급된 라이브러리를 한번도 사용해본 적이 없는데요. 이번 아티클만 보고도 바로 적용할 수 있을 만큼 사용 방법이 자세히 나와있어서 읽기 너무 편했어요!!!
recoil로 server state를 관리할 수 있다는 점을 보고, redux에서 비동기 처리를 어떻게 하는지 궁금해서 찾아봤는데, redux 자체적으로는 지원하지 않고, redux-thunk, redux-saga같은 미들웨어에서 해당 기능을 제공한다고 하네요!! 방법을 살펴봤는데 굉장히 복잡해서,,,,, react-query를 애용해야겠어요 ㅎㅎ 참고용 링크 남깁니다!!
https://velog.io/@ysg81/React-react-redux-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%B2%98%EB%A6%AC
다뤄보지 않은 라이브러리를 알기 쉽고 친절하게 설명해주셔서 정말 유익했던 아티클이었어요!!! 아티클 작성하느라 고생하셨습니다!!!!
유용한 아티클 공유 감사합니다!
항상 client state, server state에 대해 헷갈렸었는데 이 아티클에서 잘 정리해주셔서 덕분에 평소 모호하게 알고 있던 부분을 짚고 넘어갈수 있었습니다!
또 server state 관리 라이브러리의 예시로 react query, client state 관리 라이브러리의 예시로 recoil에 대해 자세히 설명해주셔서 이해가 쏙쏙 잘 되었습니다~
recoil로 client state 전역 관리는 사용해 본 경험이 있는데, asynchronous recoil 즉, recoil의 selector로 promise를 반환하도록 하는 형식의 data fetching은 사용해 본 경험이 없어 아티클을 읽으면서 더 흥미로웠어요! react-query 역시 심화적으로 다뤄본적은 없어 이번 실습 내용이 더 기대 됩니다!!
전에 react-query 관련하여 서치하다가, Optimistic Update
라는 흥미로운 개념을 발견했어서 공유해봅니다!
optimistic Update
란 말 그대로 낙관적 업데이트로, 서버 업데이트시 UI에서도 어차피 업데이트 할 것이라는 (낙관적인) 가정으로 미리 UI를 업데이트 시켜주고,
그 후 서버를 통해 검증 받고 업데이트 or 롤백하는 방식을 말합니다!
좋아요와 같은, 사용자 경험을 위해 빠른 UI 업데이트가 필요한 경우 사용되는 방식이라고 해요!
react-query를 사용하면 onMutate, onError, onSettled와 같은 콜백 함수를 이용해 이 optimistic update를 쉽게 구현할수 있다는 장점이 있다고 해요!
아티클 쓰느라 고생 많으셨습니다 Ṑṑ
리액트 쿼리에 대한 사용법을 상세하고 쉽게 설명해주셔서 이해에 큰 도움이 됐습니다.
저는 리액트 쿼리를 사용하면서 고려해볼 점들을 알아보았는데요
React Query Hooks을 custom hook으로 감싸는 것
React 구성 요소에서 useQuery 및 useMutation을 직접 호출하는 대신 고유한 custom hooks로 감싸는 방법을 선택할 수 있다고합니다. 이렇게 하면 데이터 계층과 프레젠테이션 계층이 분리되어 관심사를 명확히 구분할 수 있고 API fetch function을 React 컴포넌트에서 사용할 필요가 없습니다 (관심사 분리, 단일 책임 원칙)
필요한 곳에 상태를 가까이하는 것
상태를 관리하는 것에서 props drilling은 항상 문제가 되었습니다. 필요한 상태를 가까이 배치하고 페칭 로직을 가까이 배치하는 것이 이 문제를 해결하는데 도움을 줄 수 있다고 합니다.
stale한 것이 무엇인지와 오래된 쿼리와 자동으로 다시가져오는 경우에 대해서도 알아보았는데 다음과 같다고 합니다.
리액트 쿼리에 대한 사용법을 상세하고 쉽게 설명해주셔서 이해에 큰 도움이 됐습니다.
저는 리액트 쿼리를 사용하면서 고려해볼 점들을 알아보았는데요
React Query Hooks을 custom hook으로 감싸는 것
React 구성 요소에서 useQuery 및 useMutation을 직접 호출하는 대신 고유한 custom hooks로 감싸는 방법을 선택할 수 있다고합니다. 이렇게 하면 데이터 계층과 프레젠테이션 계층이 분리되어 관심사를 명확히 구분할 수 있고 API fetch function을 React 컴포넌트에서 사용할 필요가 없습니다 (관심사 분리, 단일 책임 원칙)
필요한 곳에 상태를 가까이하는 것
상태를 관리하는 것에서 props drilling은 항상 문제가 되었습니다. 필요한 상태를 가까이 배치하고 페칭 로직을 가까이 배치하는 것이 이 문제를 해결하는데 도움을 줄 수 있다고 합니다.
stale한 것이 무엇인지와 오래된 쿼리와 자동으로 다시가져오는 경우에 대해서도 알아보았는데 다음과 같다고 합니다.
좋은 아티클 감사합니닷!! ♥
우선 저는 매번 프로젝트를 할때마다, 클라쪽 데이터, 서버쪽에서 넘겨주는 데이터 이런식으로 표현해왔는데 ,, 이렇게 명확히 client state/server state로 구분할 수 있다는 것을 처음 알게 되었어욧 ,,
그리고 recoil 설명 중 mySelector 셀렉터는 myAtom 아톰에 대해 종속된다/의존한다/구독한다
라는 표현이 있는데, 저런 관계를 종속한다, 의존한다 이런식으로 표현하는건 알고있었지만 구독한다
라고도 표현한다는건 이번에 처음 알게 되었습니다!! 사실 개발도 결국 영어 번역체가 많아서 이런 용어 하나조차도 아예 모르는 상태면 인지하지 못한채 넘어가기 쉬운데, 덕분에 알게 되어서 넘 좋았어요!
한가지 궁금했던건 recoil과 redux를 비교하는 서론에서, recoil이 명확한 단점이 있으면서도 가장 React스러운 상태관리
라는 철학이 있다고 하셨는데, 이게 어떤걸 의미하고 왜인지 궁금했습니다! 더 찾아보니, 애초에 Recoil을 소개하는 공식 문서 자체에서 recoil을 작고 React스럽다
라고 언급했더라구요! 그리고 그 이유로, 'recoil은 react처럼 작동한다. 앱에 추가하여 빠르고 유연하게 공유되는 상태를 사용할 수 있다(Recoil works and thinks like React. Add some to your app and get fast and flexible shared state.)'라고 언급되었었습니다. 공식 문서에도 더 구체적인거는 안나와서, 이번 실습때 직접 작성해보며 경험해보고싶어요!!
좋은 아티클 넘 감사합니닷!!
useQuery가 최초 mount에만 실행되고 이후에는 자동 실행이 되지 않는다는 점을 이번 아티클을 통해 처음 알게되었습니다!
useQuery가 있는데 useMutation은 왜 사용을 하는지 차이점은 뭔지 궁금해져서 찾아봤는데,
useQuery는 get method를 사용할 때, useMutation은 post, delete, patch(put) method를 사용할 때 사용된다고 하네요!
(참고 자료
https://velog.io/@citron03/React-Query에서-Post-useMutation-hook-사용하기
https://stackoverflow.com/questions/64700944/react-query-whats-the-difference-between-usequery-and-usemutation-hook
)
찾고 나니 너무나도 기본적인 이유였어가지고 초큼 당황스러웠습니다;
recoil을 한 번도 사용해 본 적 없는데, 쉽게 처음부터 설명을 해주셔서 따로 자료 안 찾아봐도 바로 코드에 적용시킬 수 있을 거 같다는 생각이 들었습니다!
recoil은 들어는 봤었지만 asynchronous recoil은 아예 처음 들어보는 거라 생소했지만 이 또한 잘 이해할 수 있었습니다!!
이번 아티클에선 정말 많은 걸 배워가는 거 같아요!!
Suspense와 ErrorBoundary도 진짜 처음 보는 개념인데 완전 신세곕니다;
react-query에 isLoading 보고 state로 관리 안 해줘도 되겠다 싱글벙글 하고 있었는데 Suspense 보고 머리 띵 치고 갑니다;
이에 대해 좀 더 공부하고 싶어서 찾아봤는데요
이와 같이 여러 개의 자식 컴포넌트가 있는 경우, 하나만 준비되었다고 해서 렌더링 되는 것이 아니라 자식들 모두 준비되었을 때 렌더링이 된다고 합니다!!
만약 이런 식으로 suspense 안에 suspense가 있는 경우,
BigSpinner는 모든 자식들을 다 기다릴 필요 없이, 내부 suspense 안의 컴포넌트를 제외한 biography만 기다린 뒤 바로 렌더링 한다고 해요!
안쪽의 suspsense는 Biography와는 상관없이 Albums가 준비되면 렌더링 합니다!
이번 주엔 합세랑 솝커톤 때문에 일정이 뽝뽝해서 요 정도까지만 공부를 했지만 나중에 더 공부를 해보고 싶어요!! (ㄹㅇ)
(참고 자료 : https://react.dev/reference/react/Suspense)
아티클 작성하시느라 너무나도 고생하셨습니다 :)