최근 근황을 짧게 말씀드리자면..음식과 관련된 사이드 프로젝트를 진행 중입니다! 🍚🍔🍖
기존 회사에서 쓰던Redux
라이브러리가 아닌React-Query
와Recoil
을 쓰기로 결정하였습니다. 해당 라이브러리들을 쓰기 전 특징과 장단점을 정리해보았습니다.
React Query는 데이터 Fetching, 캐싱, 동기화, 서버 쪽 데이터 업데이트 등을 쉽게 만들어 주는 React 라이브러리입니다.
1️⃣ React 컴포넌트 내에서 데이터 패칭, 캐싱, 상태 업데이트를 쉽게 만들어 줌.
2️⃣ React-Query는 별도의 설정 없이 즉시 사용 가능함(크기 ⬇️).
3️⃣ 같은 데이터에 대한 여러번의 요청이 있을 시 중복을 제거함(옵션에 따라 중복 호출 허용 시간 조절 가능).
React-Query를 사용해 서버 상태를 가져오기 위해서는 useQuery를 사용하면 됩니다. 만약 서버의 data를 수정하고자 한다면 useMutation 을 사용합니다.
요약하면 R ( Read ) 은 useQuery , CUD ( Create, Update, Delete )는 useMutation을 사용하면 됩니다.
useMutation
을 사용합니다.비동기
로 작동합니다. 한 컴포넌트에 여러개의 useQuery가 있다면 useQuery가 동시에 실행됩니다. ** 순착적인 비동기 query가 필요하다면 enabled
로 동기적 사용가능![예시 1]
const Todos = () => {
const { isLoading, isError, data, error } = useQuery("todos", fetchTodoList, {
refetchOnWindowFocus: false, // react-query는 사용자가 사용하는 윈도우가 다른 곳을 갔다가 다시 화면으로 돌아오면 이 함수를 재실행합니다. 그 재실행 여부 옵션 입니다.
retry: 0, // 실패시 재호출 몇번 할지
onSuccess: data => {
// 성공시 호출
console.log(data);
},
onError: e => {
// 실패시 호출 (401, 404 같은 error가 아니라 정말 api 호출이 실패한 경우만 호출됩니다.)
// 강제로 에러 발생시키려면 api단에서 throw Error 날립니다. (참조: https://react-query.tanstack.com/guides/query-functions#usage-with-fetch-and-other-clients-that-do-not-throw-by-default)
console.log(e.message);
}
});
if (isLoading) {
return <span>Loading...</span>;
}
if (isError) {
return <span>Error: {error.message}</span>;
}
return (
<ul>
{data.map(todo => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
);
};
// 또는 isLoading, isSuccess 를 status 로 한번에 처리가 가능하다.
[예시 2]
const Todos = () => {
const { status, data, error } = useQuery("todos", fetchTodoList);
if (status === "loading") {
return <span>Loading...</span>;
}
if (status === "error") {
return <span>Error: {error.message}</span>;
}
return (
<ul>
{data.map(todo => (
<li key={todo.id}>{todo.title}</li>
))}
</ul>
);
}
✅ 'todos'
: 첫번째 인자로, unique key를 명시해줍니다.
✅ fetchTodoList
: 두번째 인자에는 우리가 요청할 비동기 함수를 넣어주는데, 데이터와 error를 return해줍니다.
주요 states
isLoading
orstatus === 'loading'
: 현재 데이터를 요청 중이나 아직 데이터가 없을 경우isError
orstatus === 'error'
: 쿼리에서 에러가 났을 경우isSuccess
orstatus === 'success'
: 쿼리 요청 성공isIdle
orstatus === 'idle'
: 이 쿼리는 현재 사용할 수 없을 때 나옴isFetching
: 데이터 요청 중일 때는 (내부적으로 리패칭 중 일때도 포함) 항상 True를 리턴한다
useMutation
은 데이터를 post, update, delete 할 때 사용됩니다.optimistic update
기능도 사용자에게 정말 좋은 경험을 제공할 수 있습니다.useMutation은 3가지 매개변수를 받습니다.
useMutation(key, function, options) 요렇게 인자 3개를 받는다
↑ ↑ ↑
쿼리키 api호출함수 쿼리옵션
✅ mutationKey
: 첫번째 인자로, unique key를 명시해줍니다.
✅ mutationFn
: 서버와 통신할 promise 처리가 이루어지는 api 함수를 의미합니다.
```jsx
const saveItem1 = useMutation((item) => axios.post('/saveItem', item));
const saveItem2 = useMutation({
mutationFn: (item) => axios.post('/saveItem', item)
})
```
✅ options
: 서버와 통신할 promise 처리가 이루어지는 api 함수를 의미합니다.
onSuccess
, onError
, onSettled
옵션을 사용가능!{
onSuccess: () => { // 요청 성공시 실행
console.log('onSuccess');
},
onError: err => { // 요청 실패시 실행
console.log('onError')
},
onSettled: () => { // 성공실패 관계없이 실행
console.log('onSettled')
},
}
invalidateQueries는 useQuery에서 사용되는 queryKey의 유효성을 제거해주는 목적으로 사용됩니다.
(서버로부터 다시 데이터를 조회해오기 위함 + 데이터를 캐싱하고 싶지 않을 때)
const queryClient = useQueryClient(); // 등록된 quieryClient 가져오기
const saveItem = useMutation((item) => axios.post('/saveItem', item), {
onSuccess: () => { // 요청이 성공한 경우
console.log('onSuccess');
queryClient.invalidateQueries('item'); // queryKey 유효성 제거
},
onError: (error) => { // 요청에 에러가 발생된 경우
console.log('onError');
},
onSettled: () => { // 요청이 성공하든, 에러가 발생되든 실행하고 싶은 경우
console.log('onSettled');
}
});
Recoil은 Facebook에서 출시된 React 전용 상태관리 라이브러리입니다. (React에 최적화)
Recoil을 사용하면 atoms (공유 상태)에서 selectors (순수 함수)를 거쳐 React 컴포넌트로 내려가는 data-flow graph를 만들 수 있습니다.
1️⃣ React 문법 친화적
2️⃣ 간단하고, 강력함.
3️⃣ 내부적으로 자동적으로 캐싱되어 빠름(side-effect 존재)
1️⃣ 안정성
0.7.6
**2️⃣ 부족한 레퍼런스
<RecoilRoot>
를 사용해야합니다.RecoilRoot
를 넣기에 가장 적합하여, App.js
에 적용합니다.// App.js
import React from 'react';
import App from './App';
import { RecoilRoot } from 'recoil';
function App() {
return (
<RecoilRoot>
<Navigator />
</RecoilRoot>
);
}
import { atom } from "recoil";
export default atom({
key: 'countState',
default: 0,
});
공식문서 설명
Selector는 파생된 상태(derived state)의 일부를 나타낸다.
파생된 상태를 어떤 방법으로든 주어진 상태를 수정하는 순수 함수에 전달된 상태의 결과물로 생각할 수 있다.
import { DefaultValue, selector } from "recoil";
import countState from "../atom/countState";
export default selector({
key: "countSelector",
get: ({get}): number => {
const count = get(countState);
return count + 1;
},
set: ({set, get}, newCount)=>{
return set(countState, newCount + 10)
}
})
https://kyounghwan01.github.io/blog/React/react-query/basic/#usequery