React Query를 이용해 api 연동시키기
React Query 란?
리액트용 data-fetching 라이브러리로,
리액트 어플리케이션에서 서버의 상태를 fetching, caching, synchronizing, updating 한다.
react query는 다음과 같이 4가지 상태를 반환하는데, 반환 상태에 따라 렌더링을 다르게 처리하기 용이하단느 장점이 있다.
isIdle
: status === ‘idle’로, fresh/reset된 상태isLoading
: status === ‘loading’으로, mutation이 진행 중인 상태isError
: status === ‘error’로, mutation이 error를 발생시킨 상태isSuccess
: status === ‘success’로, mutation이 성공하여 data 이용이 가능한 상태
설치하기
1 | $ npm i react-query |
기본 예시
App.tsx
1 | import { QueryClient, QueryClientProvider, useQuery } from 'react-query' |
가장 상단
App.js
에서 최상단 컴포넌트로QueryClientProvider
을 전달한다.해당 Provider context의 props로
queryClient
객체를 전달한다.
Example.tsx
1 | function Example() { |
useQuery
에- query key 와
-
fetch
,axios
등을 이용한 CRUD 함수 를 전달한다.
useQuery
를 통해 isLoading
, error
, data
등을 받아 렌더링 한다.
1 | if (isLoading) return 'Loading...' |
isLoading
일 때는 로딩 렌더링error
일 때는 에러 렌더링- 이 외,
data
를 정상적으로 받아온 경우 컴포넌트를 알맞게 렌더링
useQuery
useQuery
가 반환하는 프로퍼티와 받는 매개변수는 다음과 같다.
1 | const { |
이를 사용한 예시는 다음과 같다.
먼저, useQuery에 전달할 getCategoryDetail
api 함수를 작성해보자.
1 | export const getCategoryList = async () => { |
이제 해당 함수를 useQuery에 전달하여 데이터를 받아보자.
1 | const { isLoading, error, data: categoryList } = useQuery('categoryList', getCategoryList); |
여기서 categoryList
는 query key 이며, getCategoryList
를 통해 받아온 데이터는 isLoading
, error
, data
등을 담은 객체에 저장된다.
여기서 data: categoryList
로 데이터 변수명을 설정하여 컴포넌트를 알맞게 렌더링하면 된다!
useMutation
useMutation
이 반환하는 프로퍼티와 받는 매개변수는 다음과 같다.
1 | const { |
이제 useMutation을 사용해보자!
1 | export const postItem = async (data: Item) => { |
위와 같이 정의한 postItem
api를 받아 mutation을 적용해보자.
1 | const mutation = useMutation((data: PutBodyProps) => postItem(data), { |
먼저 전달할 인자를 postItem
에 알맞게 전달하고, onSuccess
시 queryClient
를 통해 이전에 정의해놓은 query key 값을 전달하여 데이터를 mutate 시킨다.
BOJ 7576
Input
첫 줄에는 상자의 크기를 나타내는 두 정수 M,N이 주어진다. M은 상자의 가로 칸의 수, N은 상자의 세로 칸의 수를 나타낸다. 단, 2 ≤ M,N ≤ 1,000 이다.
둘째 줄부터는 하나의 상자에 저장된 토마토들의 정보가 주어진다. 즉, 둘째 줄부터 N개의 줄에는 상자에 담긴 토마토의 정보가 주어진다. 하나의 줄에는 상자 가로줄에 들어있는 토마토의 상태가 M개의 정수로 주어진다. 정수 1은 익은 토마토, 정수 0은 익지 않은 토마토, 정수 -1은 토마토가 들어있지 않은 칸을 나타낸다.
토마토가 하나 이상 있는 경우만 입력으로 주어진다.
1 | from collections import deque |
BFS
트리가 1단계씩 깊어질 때마다 기존의 조건을 동일하게 다시 체크해야 함 == BFS
사전 준비
인접한 영역(가로,세로 =>
dir
로 방향 배열 만들어놓기)1
dir = [[-1,0],[1,0],[0,-1],[0,1]]
queue 초기화 시
1
인 위치를 넣어놓는 배열1
2
3
4
5
6ripen = deque()
for i in range(N):
for j in range(M):
if tomato[i][j] == 1:
ripen.append([i, j])이미 모두
1
인 경우를 체크할isAlready
boolean1
isAlready = True
- 체크하고 있는 칸이 범위 내이며
0
일 경우 의 값을+1
한다.
1 | def bfs(): |
- 이미 모두
1
인 경우isAlready
boolean 값을 이용해 조건에 맞게 답을 출력한다. - 배열 전체가
True
가 아닌 경우를 체크해야 하므로all
을 이용한다. - 이 외,
bfs
의 결과 출력을 위해 배열 전체에서max
값을 추출한다.
1 | if not all(map(all,tomato)): |
위 모두에서 유용하게 쓰인 python 문법: 2차원 배열에서 최종값 하나 출력을 위해…
1 | max(map(max, tomato)) |
Output
여러분은 토마토가 모두 익을 때까지의 최소 날짜를 출력해야 한다. 만약, 저장될 때부터 모든 토마토가 익어있는 상태이면 0을 출력해야 하고, 토마토가 모두 익지는 못하는 상황이면 -1을 출력해야 한다.
1 | bfs() |
BOJ 10971
Input
첫째 줄에 도시의 수 N이 주어진다. (2 ≤ N ≤ 10)
다음 N개의 줄에는 비용 행렬이 주어진다. 각 행렬의 성분은 1,000,000 이하의 양의 정수이며, 갈 수 없는 경우는 0이 주어진다. W[i][j]는 도시 i에서 j로 가기 위한 비용을 나타낸다.
항상 순회할 수 있는 경우만 입력으로 주어진다.
1 | import sys |
DFS
시작점을 모두 다르게 해서 탐색해야 하므로
for
문으로 dfs 실행1
2for now in range(N):
dfs(now, now, 0, [now])시작점이 아니며,
visited == False
이며,cost != 0
인 경우 dfs 실행- 실행 시 visited
True
체크 했다가 모든 확인을 마치고return
후 dfs를 빠져나오면 해당 노드를False
체크하여 다음 경우의 수를 검사하도록 함
1
2
3
4
5for idx in range(N):
if cost[next][idx] != 0 and idx not in visited:
visited.append(idx)
dfs(start, idx, total + cost[next][idx], visited)
visited.pop()- 실행 시 visited
visited
의 길이가N
인 경우 모든 노드를 방문한 것이므로start
지점으로 돌아와야 한다. 이 때cost != 0
이라면min
을 업데이트한다.1
2
3
4if len(visited) == N:
if cost[next][start] != 0:
minCost = min(minCost, total + cost[next][start])
return가장 중요한 것은: 현재
total
값이 이미minCost
를 초과한 경우,return
을 통해 빠져나와야 시간 초과가 뜨지 않는다!!!
Output
첫째 줄에 외판원의 순회에 필요한 최소 비용을 출력한다.
1 | if len(visited) == N: |
Git Flow
Git
VCS(Version Control System)
- 오픈 소스 프로젝트에 contribute 가능
Index/ Staging Area

Git Flow
feature > develop > release > hotfix > master
- master
- production에 사용되는 브랜치
- feature
- 브랜치 나오는 곳 :
develop
- 브랜치가 들어가는 곳 :
develop
- 이름 지정 :
master
,develop
,release-*
,hotfix-*
를 제외한 어떤 것이든 가능. - 새로운 기능을 추가하는 브랜치
origin
에는 반영하지 않고개발자의 repo
에만 존재- 여기서 merge를 할 때,
--no-ff
옵션을 이용하여 브런치에서 머지가 되었음을 git 기록에 남겨두도록 함
- 브랜치 나오는 곳 :
- release
- 브랜치 나오는 곳 :
develop
- 브랜치가 들어가는 곳 :
develop
,master
- 이름 지정 :
release-*
- 새로운 production release를 위한 브랜치
- 현재까지의 기능을
develop
에서release
로 따오고,develop
에는 다음번 릴리즈를 준비한다. 그리고 다가오는 릴리즈를 위해서release
브랜치에서 버그 픽스에 대한 부분만 커밋하고, 최종적으로master
로--no-ff
한다.
- 브랜치 나오는 곳 :
- hotfix
- 브랜치 나오는 곳 :
master
- 브랜치가 들어가는 곳 :
develop
,master
- 이름 지정 :
hotfix-*
- production에서 발생한 문제를 해결하는 브랜치
- 만약
release
브런치가 존재한다면,release
브런치에hotfix
브런치를 머지하여 릴리즈 될 때 반영이 될 수 있도록 한다.
- 브랜치 나오는 곳 :
BOJ 2606
Input
첫째 줄에는 컴퓨터의 수가 주어진다. 컴퓨터의 수는 100 이하이고 각 컴퓨터에는 1번 부터 차례대로 번호가 매겨진다.
둘째 줄에는 네트워크 상에서 직접 연결되어 있는 컴퓨터 쌍의 수가 주어진다.
이어서 그 수만큼 한 줄에 한 쌍씩 네트워크 상에서 직접 연결되어 있는 컴퓨터의 번호 쌍이 주어진다.
1 | import sys |
연결되어 있는 경우
connected
배열에 연결된index
를 append 한다!
1 | for _ in range(pair): |
DFS
- 전달된 인자를
visited = True
설정하고, - 해당 인자를 connected의 index로 설정하여 연결된 컴퓨터들을 찾는다.
- 이 때, 연결된 컴퓨터가
not visited
일 경우 재귀 호출
1 | visited = [False]*(N+1) |
- 1번이 걸린 경우 이어서 걸릴 애들을 세는 것이므로
count = -1
로 초기화하고 세기 시작한다.
1 | count = -1 |
Output
1번 컴퓨터가 웜 바이러스에 걸렸을 때, 1번 컴퓨터를 통해 웜 바이러스에 걸리게 되는 컴퓨터의 수를 첫째 줄에 출력한다.
1 | dfs(1) |
BOJ 1697
Input
Default
- 런타임에러 방지를 위해
sys.stdin
과sys.stdout
을 이용한다.
첫 번째 줄에 수빈이가 있는 위치 N과 동생이 있는 위치 K가 주어진다. N과 K는 정수이다.
1 | import sys |
BFS
- 이진 탐색 그래프에서 가장 얕은 깊이를 출력하면 됨 == BFS
1 | def bfs(): |
now == K
일 때, 해당 깊이를 출력하면 됨
1 | if now == K: |
- 그래프를 그리며 경우의 수를 파악하였지만, 모든 경우에 대하여 bfs 하는 것을 생각하지 못함
now-1
,now+1
,2*now
- 주어진 범위에 따라 범위 내의 값인지 파악하고
- 한 단계 더 깊어질 경우
깊이 == 현재의 높이+1
이므로,cnt += 1
을 시행한다. - 이를 위해 0으로 초기화된 범위 만큼의 배열을 생성한다.
1 | cnt = [0]*100001 |
1 | for next in (now-1, now+1, 2*now): |
Output
수빈이가 동생을 찾는 가장 빠른 시간을 출력한다.
1 | if now == K: |
BOJ 11724
Input
python을 사용할 때 시간 초과 를 방지하기 위해,
sys
를 이용하여
sys.stdin.readline()
혹은sys.stdout.write()
를 사용한다!
sys.stdout.write()
의args
는 string 이어야 하므로,str()
를 사용할 것!
첫째 줄에 정점의 개수 N과 간선의 개수 M이 주어진다. (1 ≤ N ≤ 1,000, 0 ≤ M ≤ N×(N-1)/2)
둘째 줄부터 M개의 줄에 간선의 양 끝점 u와 v가 주어진다. (1 ≤ u, v ≤ N, u ≠ v) 같은 간선은 한 번만 주어진다.
1 | N, M = map(int, sys.stdin.readline().split()) |
DFS
- 일단
visited = True
로 체크하고, adj
배열의 요소를 전부 돌면서 아직visited
하지 않은 경우 같은 과정을 반복하며visited = True
로 체크한다. == DFS
1 | def dfs(u): |
Default
- 재귀함수 문제에서는 항상
sys.setrecursionlimit()
를 설정하자.
1 | import sys |
1 | count = 0 |
Wrong Answer
처음 시도했던 방법은 아래와 같은데, 시간 초과 가 뜸.
1 | graph = [list(map(int, input().split())) for _ in range(M)] |
다른 부분은
input()
과,입력을 근접한 노드를 담는
adj
대신 그대로 저장하는 2차원 배열graph
을 사용한 것 뿐인데
sys
을 이용해도 위 코드가 시간 초과 가 뜨는 이유는 무엇일까?
; 이유는 위 코드는 근접한 노드만을 하나씩 돌며 dfs를 실행하는 것이 아니라,
- 주어진 조건을 모두 다시 돌며
index == 0
의 값이 해당 값인지 체크하고, - 같을 때 dfs를 실행해야 하므로 N, M가 클 때는 배열을 전부 다시 탐색하는 것이 근접한 노드만 검사할 때보다 훨씬 시간이 많이 필요하기 때문.
Output
첫째 줄에 연결 요소의 개수를 출력한다.
1 | sys.stdout.write(str(count)) |
리스트 초기화
multiplication 과 for문의 차이
- multiplication
1 | >>> a = [[1]*8]*8 |
- for
1 | >>> A = [[1 for i in range(8)] for j in range(8)] |
In your first version, you’re creating a list containing the number 1 and by multiplying it 8 times create a list containing 8 1s, and using that list 8 times to create a
.
So when you change anything in the first version, you’ll see that change everywhere else. Your problem being that you’re reusing the same instance, something that doesn’t happen in the second version.
BOJ 2468
Input
1 | N = int(input()) |
DFS
recursion limit 설정하기
이 문제를 파이썬에서 풀기 위해서 무조건
sys.setrecursionlimit()
을 추가해줘야 한다. 이 코드를 삽입하지 않으면 런타임 에러가 발생한다. 공식 도큐먼트에 의하면 해당 코드는 파이썬 인터프리터 stack에 최대 깊이를 지정하는 것이다. 무한대의 recursion이 발생해서 overflow가 발생하는 것을 방지하기 위함이다. 이 문제에서는 그 만큼 깊이 있게 recursion으로 stack이 쌓이기 때문에 어느 정도가 진행되면 제한을 둬야 하는 것이다.ref > https://dojinkimm.github.io/problem_solving/2019/11/15/boj-2468-safezone.html
recursion
을 사용할 때 runtime error 가 발생한다면sys.setrecursionlimit()
을 설정하자!!
1 | import sys |
direction 배열 선언해놓기
- 배열로 x, y 한번에 만들어도 좋고
- x, y 따로 선언해서 같은 index로 접근해도 좋다.
1 | dir = [[-1,0],[1,0],[0,-1],[0,1]] |
visited 배열 생성하기
1 | visited = [[0]*N for _ in range(N)] |
조건
- 가능한 높이를 조건에 따라 세팅해놓고,
- 매번 비교하며
max
값을 구해야 하므로 기본 변수들을 초기화시킨다.
1 | maxHeight = 100 |
- 영역을 연속적으로 구하는 것이므로, 동일한 조건을 동일하게 반복하며 실행한다 === DFS
1 | def dfs(dy, dx): |
- 2차원 배열을 모두 돌며 조건에 맞는 경우 DFS
- 방문하지 않음
- 고도가 기준보다 높거나 같음 (잠기지 않음)
- 이후 빠져나온 경우는 영역이 정해졌다는 의미이므로
count++
를 실행한다.
1 | for i in range(N): |
- 배열을 모두 검사하면 해당
height
에 대한 검사가 완료되었다는 뜻이므로max
값을 구한다.
1 | maxCount = max(maxCount, count) |
Output
첫째 줄에 장마철에 물에 잠기지 않는 안전한 영역의 최대 개수를 출력한다.
1 | print(maxCount) |