티스토리 뷰
React Query
- React 애플리케이션에서 데이터 관리를 위한 JavaScript 라이브러리
- 비동기 데이터를 관리하고 캐싱하며, 상태 관리와 관련된 작업을 쉽게 처리할 수 있다
- Redux는 비동기 데이터 관리를 위한 전문 라이브러리가 아니며, Redux-thunk의 보일러 플레이트가 많다는 단점을 보완하기 위해 사용된다
- 비동기 통신을 위해 사용되므로 json-servser(파이어베이스, 수파베이스도 상관없음) 등의 서버를 연결해 사용하며 axios(fetch도 상관없음) 설치도 필요하다(비동기 통신을 해야 하니까)
설치 명령어
npm | yarn |
npm install react-query | yarn add react-query |
Query
요청을 의미하며 서버로부터 데이터를 요청한다 CRUD 중, R(Read)에 해당한다 axios의 경우 get 요청과 비슷하다
Mutation
CRUD 중, CUD (Create, Update, Delete)에 해당하며, 변경을 의미한다 axios의 경우 post, put, patch, delete 요청과 비슷하다
Query Invalidation
추가, 변경 등이 일어난 경우 서버와 애플리케이션의 데이터를 동일하게 만들기 위해 기존에 가져온 데이터를 무효화(지우고) 새로 가져오는 것
React Query 설정
- 최상위 컴포넌트에 QueryClient()를 만들어 준다, QueryClient는 서버로부터 받은 데이터를 저장하는 역할을 한다
- Redux에서 Provider로 전역상태를 관리한 것과 동일하게 <Queryclientprovider client={queryclient}>를 최상위 컴포넌트에 주입하여 안에 하위 컴포넌트를 연결해 주면 서버 데이터를 전역에서 사용할 수 있게 된다
const queryClient = new QueryClient();
const App = () => {
return (
<QueryClientProvider client={queryClient}>
<Router />
</QueryClientProvider>
);
};
API파일 만들기(axios 등 서버통신 함수를 모아놓은 파일)
- 비동기 통신 함수를 모아놓은 파일을 생성하며 함수를 export 해줘 외부에서 import 할 수 있게 한다
- 아래 코드는 axios를 사용했으므로 문법 그대로 사용하면 되며, 서버에 요청하는 부분은 .env파일의 변수명을 넣어줬다
- 데이터 추가 함수에는 새 todo가 들어가야 하므로 인자값으로 넣어줬다
// axios 요청이 들어가는 모든 모듈
import axios from "axios";
// 조회
const getTodos = async () => {
const response = await axios.get(`${process.env.REACT_APP_SERVER_URL}/todos`);
console.log("response", response.data);
return response.data;
};
// 추가
const addTodo = async (newTodo) => {
await axios.post(`${process.env.REACT_APP_SERVER_URL}/todos`, newTodo);
};
export { getTodos, addTodo };
데이터 조회하기
- Query를 사용하므로 useSelector가 아닌 useQuery를 사용한다
- useQuery는 isLoading, isError, data가 내장되어 있고(data가 서버에서 가져온 데이터) Thunk를 사용하지 않고도 미들웨어를 사용할 수 있다
- useQuery는 인자가 2개 들어간다 쿼리 이름(Query key), api 폴더에 만들어놓은 비동기 함수(Query key를 기준으로 DB를 가져올 수 있고 유일한 값이 여야 한다. 중복허용 안 함)
function TodoList({ isActive }) {
const { isLoading, isError, data } = useQuery("todos", getTodos);
if (isLoading) {
return <h1>로딩중 입니다...</h1>;
}
if (isError) {
return <h1>오류가 발생하였습니다</h1>;
}
return (
<StyledDiv>
<StyledTodoListHeader>
{isActive ? "해야 할 일 ⛱" : "완료한 일 ✅"}
</StyledTodoListHeader>
<StyledTodoListBox>
{data
.filter((item) => item.isDone === !isActive)
.map((item) => {
return <Todo key={item.id} todo={item} isActive={isActive} />;
})}
</StyledTodoListBox>
</StyledDiv>
);
}
export default TodoList;
데이터 추가하기
- 상위 컴포넌트에서 newQueryClient를 이용해 서버에서 받아온 데이터를 useQueryClient를 이용해 데이터를 추가, 변경해 줄 수 있다(조회에선 사용 안 함)
- mutation은 2개의 인자를 받는다 api 컴포넌트에서 만든 비동기 함수, 객체(변경 성공 / 실패 시 실행하는 콜백함수)
- 추가 또는 변경 성공 시 실행하는 콜백함수에는 queryClient.invalidateQueries("todoList 컴포넌트의 useQuery key값으로 넣은 todos")으로 기존 데이터를 무효화하고 DB에 저장된 데이터를 새로 가져오도록 하면 데이터가 추가될 때마다 api 컴포넌트의 getTodos를 실행시킨다(서버와 애플리케이션의 데이터를 동일하게 하기 위해)
- 추가 또는 변경 함수 안에 Redux의 dispatch처럼 mutation.mutate(api 컴포넌트에서 만든 비동기 함수에 전달할 인자)를 넣어주면 된다
- mutation.mutate로 전달할 인자가 1개 이상인 경우 배열로 감싸준다 ( ex. mutation.mutate([인자 1, 인자 2]) ) 보내는 곳, 받는 곳(api파일의 axios함수) 동일하게 적용시켜 줄 것
쿼리에 관한 코드 제외 삭제했기 때문에 해당 아래 코드는 정상 작동하지 않는다
function Input() {
// 리액트 쿼리 코드
const queryClient = useQueryClient();
const mutation = useMutation(addTodo, {
onSuccess: () => {
queryClient.invalidateQueries("todos");
console.log("성공했습니다");
},
});
const handleSubmitButtonClick = (event) => {
event.preventDefault();
// 추가하려는 todo를 newTodo라는 객체로 새로 만듦
const newTodo = {
title,
contents,
isDone: false,
id: uuidv4(),
};
// 여기에 api newTodo를 넣어주면 추가 기능이 동작하게 된다.
mutation.mutate(newTodo);
setTitle("");
setContents("");
};
return (
<StyledDiv>
<form onSubmit={handleSubmitButtonClick}>
<FlexDiv>
<RightMarginBox margin={10}>
<LabledInput
id="title"
label="제목"
placeholder="제목을 입력해주세요."
value={title}
onChange={handleTitleChange}
/>
<HeightBox height={10} />
<LabledInput
id="contents"
label="내용"
placeholder="내용을 입력해주세요."
value={contents}
onChange={handleContentsChange}
/>
</RightMarginBox>
<StyledButton type="submit">제출</StyledButton>
</FlexDiv>
</form>
</StyledDiv>
);
}
export default Input;
Query Keys
- Query Keys는 유니크한 값이 여야 한다 값을 조회, 경신하는 데 사용된다(애플리케이션에 서버에 저장된 값을 가져오기 위해 사용)
- useQuery를 통해 얻은 결과물은 객체(object)이다
ex ) * 배열과 객체의 차이를 이해할 것
배열은 순서가 있기 때문에 유니크한 쿼리키다
useQuery(['todos' , status , page], ...)
useQuery(['todos' , page , status], ...)
객체는 순서가 없기 때문에 유니크하지 않은 쿼리키다
useQuery(['todos' , {status , page}], ...)
useQuery(['todos' , {page , status}], ...)
'React' 카테고리의 다른 글
[리액트 React] 인증/인가(쿠키, 세션, 토큰, JWT) (0) | 2024.03.17 |
---|---|
[리액트 React] 청크로 비동기 함수 사용 (Thunk에서 Promise 다루기) (0) | 2024.03.17 |
[리액트 React] 리덕스 미들웨어, 청크 (Thunk) (0) | 2024.03.17 |
[리액트 React] 엑시오스 인터셉터(Axios interceptor) (0) | 2024.03.16 |
[리액트 React] 페치, 엑시오스 차이 (Fetch , Axios) (0) | 2024.03.16 |