- React Redux Toolkit Query Tutorial and RTK Query CRUD Example App
https://youtu.be/HyZzCHgG3AY?list=PL0Zuz27SZ-6M1J5I1w2-uZx36Qp6qhjKo- React Toolkit RTK 공식문서
https://redux-toolkit.js.org/introduction/getting-started- React Toolkit RTK 공식문서 한글 번역
https://junsangyu.gitbook.io/rtk-query/- 리덕스 툴킷 정리 블로그
http://blog.hwahae.co.kr/all/tech/tech-tech/6946/
RTK Query는 강력한 data fetching, caching 툴입니다. 웹 애플리케이션에서 데이터를 가져오는 단순한 상황을 간단하게 만들어서 data fetching과 caching 로직을 스스로 작성할 필요가 없도록 만들어졌습니다.
npm i json-server -g
json-server --watch data/db.json --port 3500
서버를 실행시키면 데이터를 보기시작하며 읽기 업데이트 및 삭제 기능을 지원합니다.
{
"todos": [
{
"userId": 1,
"id": 2,
"title": "quis ut nam facilis et officia qui",
"completed": true
},
{
"userId": 1,
"id": 6,
"title": "qui ullam ratione quibusdam voluptatem quia omnis",
"completed": false
},
{
"userId": 1,
"id": 8,
"title": "quo adipisci enim quam ut ab",
"completed": true
},
{
...
사전에 미리 주어지는 TodoList 코드입니다.
import TodoList from "./features/todos/TodoList";
function App() {
return <TodoList />
}
export default App;
TodoList를 반환합니다.
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
export const apiSlice = createApi({
reducerPath: 'api', //default, 생략가능
baseQuery: fetchBaseQuery({ baseUrl: 'http://localhost:3500' }),
tagTypes: ['Todos'],
endpoints: (builder) => ({
// 사용자 정의 Hook
getTodos: builder.query({
query: () => '/todos',
transformResponse: res => res.sort((a, b) => b.id - a.id), // (1)
providesTags: ['Todos'] // (2)
}),
addTodo: builder.mutation({ // (3)
query: (todo) => ({
url: '/todos',
method: 'POST',
body: todo
}),
invalidatesTags: ['Todos'] // (2)
}),
updateTodo: builder.mutation({
query: (todo) => ({
url: `/todos/${todo.id}`,
method: 'PATCH',
body: todo
}),
invalidatesTags: ['Todos']
}),
deleteTodo: builder.mutation({
query: ({ id }) => ({ // (4)
url: `/todos/${id}`,
method: 'DELETE',
body: id
}),
invalidatesTags: ['Todos']
}),
})
})
export const {
useGetTodosQuery,
useAddTodoMutation,
useUpdateTodoMutation,
useDeleteTodoMutation
} = apiSlice
transformResponse: res => res.sort((a, b) => b.id - a.id),
a - b 오름차순 정렬
b - a 내림차순 정렬
데이터를 추가하면 id는 1씩 증가하면서 부여되기때문에 최근에 추가한 데이터가
제일 상단에 오도록 하려면 내림차순 정렬해야합니다.
providesTags: ['Todos']
,invalidatesTags: ['Todos']
getTodos에 Todos 태그를 주고, invalidatesTags하면 getTodos를 무효화해줍니다. 이렇게 하면 캐시에서 다시 가져오거나 제거할 캐시된 데이터가 결정됩니다.
이로써 얻을 수 있는 효과는 해당 쿼리가 실행되면 providesTags가 자동으로 패치되도록 해줍니다.
: builder.mutation()
query: ({ id }) => ({
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import { ApiProvider } from "@reduxjs/toolkit/query/react";
import { apiSlice } from "./features/api/apiSlice";
ReactDOM.createRoot(document.getElementById('root'))
.render(
<React.StrictMode>
<ApiProvider api={apiSlice}>
<App />
</ApiProvider>
</React.StrictMode>
);
ApiProvider
apiSlice
이 두가지를 import하고 App을 감싸줍니다.
import {
useGetTodosQuery,
useUpdateTodoMutation,
useDeleteTodoMutation,
useAddTodoMutation
} from "../api/apiSlice"
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { faTrash, faUpload } from '@fortawesome/free-solid-svg-icons'
import { useState } from "react"
const TodoList = () => {
const [newTodo, setNewTodo] = useState('')
const {
data: todos,
isLoading,
isSuccess,
isError,
error
} = useGetTodosQuery()
const [addTodo] = useAddTodoMutation()
const [updateTodo] = useUpdateTodoMutation()
const [deleteTodo] = useDeleteTodoMutation()
const handleSubmit = (e) => {
e.preventDefault();
addTodo({ userId: 1, title: newTodo, completed: false })
setNewTodo('')
}
const newItemSection =
<form onSubmit={handleSubmit}>
<label htmlFor="new-todo">Enter a new todo item</label>
<div className="new-todo">
<input
type="text"
id="new-todo"
value={newTodo}
onChange={(e) => setNewTodo(e.target.value)}
placeholder="Enter new todo"
/>
</div>
<button className="submit">
<FontAwesomeIcon icon={faUpload} />
</button>
</form>
let content;
if (isLoading) {
content = <p>Loading...</p>
} else if (isSuccess) {
content = todos.map(todo => { //JSON.stringify(todos)
return (
<article key={todo.id}>
<div className="todo">
<input
type="checkbox"
checked={todo.completed}
id={todo.id}
onChange={() => updateTodo({ ...todo, completed: !todo.completed })}
/>
<label htmlFor={todo.id}>{todo.title}</label>
</div>
<button className="trash" onClick={() => deleteTodo({ id: todo.id })}>
<FontAwesomeIcon icon={faTrash} />
</button>
</article>
)
})
} else if (isError) {
content = <p>{error}</p>
}
return (
<main>
<h1>Todo List</h1>
{newItemSection}
{content}
</main>
)
}
export default TodoList
todo를 입력하고 버튼을 누르면 리스트 상단에 가장 최근에 추가한 밥먹기가 추가됩니다.
http://localhost:3500/todos 에 가보면 todos에 밥먹기가 새로 추가된 걸 볼 수 있습니다.
Todo List에 밥먹기를 추가(POST)/완료처리(PATCH)/삭제(DELETE)하는 과정을 cmd창에서 보면 이렇습니다. 각각 요청을 보낸 뒤 GET으로 바로 변경한 내용을 반영해서 화면을 띄워줍니다.