기존 코드
import React, { useState } from "react";
function App() {
const [title, setTitle] = useState("");
const [comment, setComment] = useState("");
const onTitleHandler = (event) => {
setTitle(event.target.value);
};
const onCommentHandler = (event) => {
setComment(event.target.value);
};
return (
<div>
<input value={title} onChange={onTitleHandler} />
<input value={comment} onChange={onCommentHandler} />
</div>
);
}
export default App;
커스텀 훅
hooks/useInput.js
import { useState } from "react";
const useInput = () => {
const [value, setValue] = useState("");
const handler = (event) => {
setValue(event.target.value);
};
return [value, handler];
};
export default useInput;
App.js
import React, { useState } from "react";
import useInput from "./hooks/useInput";
function App() {
const [title, onTitleHandler] = useInput("");
const [comment, onCommentHandler] = useInput("");
return (
<div>
<input value={title} onChange={onTitleHandler} />
<input value={comment} onChange={onCommentHandler} />
</div>
);
}
export default App;
기존 미들웨어의 한계
리액트 쿼리의 장점
리액트 쿼리의 키워드
기본 셋팅
App.js
import React from "react";
import { QueryClient, QueryClientProvider } from "react-query";
import Router from "./shared/Router";
const queryClient = new QueryClient();
const App = () => {
return (
<QueryClientProvider client={queryClient}>
<Router />
</QueryClientProvider>
);
};
export default App;
api/todos.js
import axios from "axios";
const getTodos = async () => {
const response = await axios.get(`http://localhost:4000/todos`);
return response.data;
};
const addTodo = async (newTodo) => {
await axios.post(`http://localhost:4000/todos`, newTodo);
};
export { getTodos, addTodo };
components/Todolist.js
import React from "react";
import Todo from "../Todo";
import { getTodos } from "../../../api/todos";
import { useQuery } from "react-query";
function TodoList({ isActive }) {
// const todos = useSelector((state) => state.todos);
const { isLoading, isError, data } = useQuery("todos", getTodos);
if (isLoading) {
return <div>로딩중입니다..</div>;
}
if (isError) {
return <div>에러입니다..</div>;
}
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;
components/Input.js
import { addTodo } from "../../../api/todos";
import { useMutation, useQueryClient } from "react-query";
function Input() {
const dispatch = useDispatch();
const queryClient = useQueryClient();
const mutation = useMutation(addTodo, {
onSuccess: () => {
queryClient.invalidateQueries("todos");
},
});
const newTodo = {
id:id,
title:title,
content:content
]
// dispatch(addTodo(newTodo));
mutation.mutate(newTodo);
1.App.js에서 new QueryClient를 만들고, Provider처럼 감싸준다.
2.api폴더를 만들고 그 안에서 axio를 활용한다.
3.get방식으로 불러오는 getTodos와 post방식으로 newTodo값을 입력할 addTodo를 만들고 export로 내보낸다.
4.이제 이 방식으로 useSelector를 활용하여 데이터를 불러올 필요가 없어진다. 필요한 곳에서(todolist.js)데이터를 불러오기 위해 useQuery를 사용한다.
5.이때 내가 정할 name 키워드('todos')를 꼭 넣어주고, 만든 getTodos를 인자로 같이 넣어준다.
6.리액트 쿼리는 isLoading, isError, data를 기본적으로 탑재하고 있으므로, if문을 써서 상황을 나눠준다.
7.밑에 return문에도 이제 useSelector로 데이터를 불러오지 않고, 알아서 data에 저장되었기 때문에 data로 map을 돌릴 수 있다.
8.input값을 입력하는 곳에서도(Input.js) useQueryClient를 선언해주고,
9.입력값을 받아 입력하기 위해 mutation을 활용한다. 만들어온 addTodo를 불러와 넣어주고, onSuccess를 넣어 성공했을 시 함수를 실행시킨다.
10.queryClient를 무효화시키고, 최신화시키기 위해 만들어놓은 useQuery의 키워드 값을 가져온다(쿼리키 'todos')
=> input값에 입력을 하고 확인을 누르는 순간, mutation.mutate가 동작이 되면서(post)데이터는 입력이 된다. onSuccess가 발동이 되고, queryClient에 있는 invalidateQueries가 발동이 되면서, 우리가 원래 읽어왔었던 todos는 맞지 않아(최신이 아니야!) invalidation할거야 하면서 다시 실행해주겠다는 로직이다.