Fetch ๋ง๊ณ Axios (Feat.Refresh Token, Context)

Refresh Token์ ์ฌ์ฉํ๊ธฐ ์ํด์๋ ์์ฒญ๋ค์ด ํ ๊ณณ์์ ๊ด๋ฆฌ๋์ด์ผ ํ๋ค.
์ฌ๊ธฐ์ ๊ธฐ ์ฐ์ฌ๋์ด ์๋ fetch๋ค์ Axios๋ฅผ ์ฌ์ฉํด ์น ๋ฐ๊ฟ๋ณธ ํ๊ธฐ.
- 1. Axios๊ฐ ๋ญ๋ฐ?
- 2. Axios๋ฅผ ํ์ฉํด ํ ํฐ ์ฌ๋ฐ๊ธ ๋ฐ๊ธฐ
- 3. Axios Instance๋ฅผ ๋ชจ๋ ์ปดํฌ๋ํธ์์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ
- 4. ํ ํฐ ์ฌ๋ฐ๊ธ ์ค ์์ฑ๋ ์์ฒญ์ ๋ํ ์ฒ๋ฆฌ
- 5. Fetch ๋ง๊ณ Axios ์ฌ์ฉํ๊ธฐ
1. Axios๊ฐ ๋ญ๋ฐ?
Axios๋ JavaScript๋ฅผ ์ํ ๊ฐ๋ ฅํ HTTP ํด๋ผ์ด์ธํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค ํ๋์ด๋ค.
๊ฐํธํ HTTP ์์ฒญ(GET, POST, PUT, DELETE)์ ์์ฑํ ์ ์๊ณ , Promise ๊ธฐ๋ฐ์ด๊ธฐ ๋๋ฌธ์ ๋น๋๊ธฐ ์์
์ ํจ์จ์ ์ผ๋ก ์ฒ๋ฆฌํ ์ ์๋ค.
? ๊ทธ๊ฑด fetch๋ ์์์
๋ง๋ค.
๊ฐ๋จํ HTTP ์์ฒญ์ ์ฒ๋ฆฌํด์ผํ๋ค๋ฉด fetch๋ฅผ ์ฌ์ฉํด๋ ๋์ง๋ง, ๋ชจ๋ ์์ฒญ์ ๋์ผํ ์ค์ (eg. baseURL, headers, etc)์ ์ ์ฉํด์ผ ํ๋ค๋ ์ง, ์๋ฌ๊ฐ ๋ฐ์ํ์ ๋ ๋์ผํ ์ฒ๋ฆฌ๊ฐ ํ์ํ๋ค๋ ์ง, ์ด๋ฐ ์ค์ํ๋ ๊ด๋ฆฌ๋ฅผ ํ๋ ค๋ฉด axios๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค.
cf. HTTP ์์ฒญ์ ์ฒ๋ฆฌํ๋ ๋๋ค๋ฅธ JavaScript ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก Superagent๊ฐ ์๋ค๋ง, ๋ ๋ง์ด ์ฌ์ฉ๋๊ณ ๋ ์์ฃผ ์
๋ฐ์ดํธ ๋๋ Axios๋ฅผ ๊ณจ๋๋ค.
๋ฟ๋ง ์๋๋ผ axios๋ฅผ ์ฌ์ฉํ๋ฉด ์๋์ผ๋ก JSON ํ์ฑ๋ ํด์ฃผ๊ณ , ๋ณด๋ค ๊ฐ๊ฒฐํ ๋ฌธ๋ฒ์ผ๋ก ์์ฒญ๋ค์ ์ฒ๋ฆฌํ ์ ์๋ค.
๋์ ๊ฒฝ์ฐ์๋ ์๋ฌ๊ฐ ๋ฐ์ํ์ ๋ ๋์ผํ ์ฒ๋ฆฌ๊ฐ ํ์ํด์ axios๋ฅผ ๋์
ํ๊ฒ ๋์๋ค.
๊ทธ ๊น์ baseURL์ด๋ headers๋ ๊ณตํต์ผ๋ก ์ค์ ํด์ฃผ๋ฉฐ ์ฑ ์ฌ๊ธฐ์ ๊ธฐ์ ์ฌ์ฉํ๋ fetch๋ค์ axios instance๋ฅผ ํ์ฉํด ์ ๋ถ ๋ฐ๊ฟ๋ณด์๋ค.
2. Axios๋ฅผ ํ์ฉํด ํ ํฐ ์ฌ๋ฐ๊ธ ๋ฐ๊ธฐ
axios๋ฅผ ํ์ฉํด์ ํ ํฐ์ ์ฌ๋ฐ๊ธ ๋ฐ๋ ํ๋ก์ธ์ค๋ฅผ ๊ตฌํํ๋ ค๋ฉด,
1.axios instance๋ฅผ ์์ฑํ๊ณ
import axios from 'axios';
const instance = axios.create({
baseURL: 'https://api.example.com',
headers: {
"Content-Type": "application/json",
'Authorization': `Bearer ${accessToken}`,
}
});
2.HTTP interceptor๋ฅผ ์ ์ํด์ผ ํ๋ค.
instance.interceptors.request.use(
async (config) => {
const expirationTime = new Date(localStorage.getItem('expirationTime'));
if (expirationTime && expirationTime < new Date()) {
const newAccessToken = await refreshToken();
config.headers.Authorization = `Bearer ${newAccessToken}`;
localStorage.setItem('accessToken', newAccessToken);
}
return config;
},
(error) => {
return Promise.reject(error);
}
);
async function refreshToken() {
const refreshToken = localStorage.getItem('refreshToken');
const response = await axios.post('https://auth.example.com/token', {
grant_type: 'refresh_token',
refresh_token: refreshToken
});
const { access_token } = response.data;
const expirationTime = new Date();
expirationTime.setSeconds(expirationTime.getSeconds() + response.data.expires_in);
localStorage.setItem('accessToken', access_token);
localStorage.setItem('expirationTime', expirationTime.getTime());
return access_token;
}
์ ์ฝ๋๋ ์์ฒญ์ ๋ณด๋ด๊ธฐ ์ ์ ํ ํฐ์ ๋ง๋ฃ ์๊ฐ์ ํ์ธํ๊ณ ๋ง๋ฃ๋์๋ค๋ฉด refreshToken์ ์ด์ฉํด ์ฌ๋ฐ๊ธ ๋ฐ๋ ์์์ด๋ค.
์ค์ ๋ก ์ฌ์ฉํ๊ธฐ ์ํด์๋ ๊ณ ๋ คํด์ผํ ๊ฒ๋ค์ด ์กฐ๊ธ ๋ ์๋ค.
์ฒซ์งธ, ์ด Instance๋ฅผ ์ด๋ป๊ฒ ๋ชจ๋ ์ปดํฌ๋ํธ์์ ์ฌ์ฉํ ๊ฒ์ธ๊ฐ
๋์งธ, ํ ํฐ ์ฌ๋ฐ๊ธ์ ์งํํ๋ ์ค ์์ฑ๋ ๋๋ค๋ฅธ ์์ฒญ์ ๋ํด ์ด๋ป๊ฒ ์ฒ๋ฆฌํ ๊ฒ์ธ๊ฐ
3. Axios Instance๋ฅผ ๋ชจ๋ ์ปดํฌ๋ํธ์์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ
์ฐ๋ฆฌ๊ฐ AutoRefreshToken๋ผ๋ function์ ์ธ์คํด์ค์ ์ธํฐ์ ํฐ๋ฅผ ์ ์ํ๋ค๊ณ ํ์.
๊ทธ๋ผ ์ด ์ธ์คํด์ค๋ฅผ ์ฌ์ฉํด ์์ฒญ์ ๋ณด๋ด๊ธฐ ์ํด์๋ ์ปดํฌ๋ํธ๋ง๋ค ๋ค ํจ์คํด์ฃผ๊ฑฐ๋,
์์ฒญ์ด ํ์ํ ์ปดํฌ๋ํธ๋ง๋ค ๊ฐ์ AutoRefreshToken์ importํ๊ณ , instance(์ดํ apiClient)๋ฅผ ์ด๋ ๊ฒ ๋ฐ์์ ์จ์ผํ ๊ฒ๋ง ๊ฐ๋ค.
useEffect(() => {
if (accessToken) {
setApiClient(
<AutoRefreshToken accessToken={accessToken} setAccessToken={setAccessToken} />
);
}
}, [accessToken]);
์ข ๋ ๊ฐ๋จํ ๋ฐฉ๋ฒ์ ์์๊น?
์๋ค.
Context
React์๋ Context๋ผ๋ ๊ฒ ์๊ณ , ํ์ ์ปดํฌ๋ํธ์์ props๋ฅผ ํตํด ์ผ์ผ์ด ๋๊ฒจ์ฃผ์ง ์์๋ ๋ฐ์ดํฐ๋ฅผ ๊ณต์ ํ ์ ์๊ฒ ํด์ค๋ค.
๋ฌด๋ ค React ๊ณต์ ๋ฌธ์์ useState, useEffect์ ํจ๊ป ๊ธฐ๋ณธ Hook์ผ๋ก ๋ช
์๋์ด ์๋ useContext๋ฅผ ์ด์ฉํด ์ฌ์ฉํ ์ ์๋ค.
์ด ์น๊ตฌ๋ ํ์ ์ปดํฌ๋ํธ Depth๊ฐ ๊น์ ๋ ํนํ ์ ์ฉํ๋ฐ,
import React, { useState } from 'react';
function GrandchildComponent({ message }) {
return <div>{message}</div>;
}
function ChildComponent({ message }) {
return <GrandchildComponent message={message} />;
}
function ParentComponent({ message }) {
return <ChildComponent message={message} />;
}
function App() {
const [message, setMessage] = useState('Hello from the top level!');
const changeMessage = () => {
setMessage('Updated message from the top level!');
};
return (
<div className="App">
<h1>Deep Component Tree Example</h1>
<button onClick={changeMessage}>Change Message</button>
<ParentComponent message={message} />
</div>
);
}
export default App;
์ด๋ฐ ์ฝ๋๊ฐ ์์ ๋ GrandchildComponent์์ ๋ฉ์ธ์ง๋ฅผ ๋ํ๋ด๊ธฐ ์ํด์ ParentComponene, ChildComponent์ Props๋ก ๋๊ฒจ ์ฃผ์ด์ผ๋ง ๊ฐ๋ฅํ๋ ๊ฒ์,
import React from 'react';
import { MessageProvider, useMessage } from './MessageContext';
function GrandchildComponent() {
const { message } = useMessage();
return <div>{message}</div>;
}
function ChildComponent() {
return <GrandchildComponent />;
}
function ParentComponent() {
return <ChildComponent />;
}
function App() {
...
return (
<MessageProvider>
<div className="App">
<h1>Deep Component Tree Example</h1>
<button onClick={changeMessage}>Change Message</button>
<ParentComponent />
</div>
</MessageProvider>
);
}
export default App;
์ด๋ฐ์์ผ๋ก ํ์ํ ๋ฐ์์๋ง ์ธ ์ ์๊ฒ ํด์ฃผ๊ธฐ ๋๋ฌธ์ด๋ค.
์ฌ๊ธฐ์ ๋ดค๋ ๊ฒ์ฒ๋ผ ๋ถํ์ํ๊ฒ ์ค๊ฐ ๋จ๊ณ์ ์ปดํฌ๋ํธ์๋ Props๋ฅผ ๋๊ฒจ์ค์ผ ํ๋ ๋ฌธ์ ๋ฅผ Prop Drilling์ด๋ผ๊ณ ๋ถ๋ฅด๊ณ ,
์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด Contex๋ฟ๋ง ์๋๋ผ Redux๋ MobX์ ๊ฐ์ ์ํ ๊ด๋ฆฌ ๋๊ตฌ๊ฐ ๋ง์ด ์ฌ์ฉ๋๋ค.
Context๊ฐ ์๋ Redux๋ฅผ ์ฌ์ฉํ๋ฉด ์์ํจ์๋ก๋ง ๋ณ๊ฒฝ์ด ๊ฐ๋ฅํ๊ณ ์์ธก ๊ฐ๋ฅํ ์ํ ๊ด๋ฆฌ๊ฐ ๊ฐ๋ฅํ๋ฉฐ Redux Dev Tool๋ก ๋๋ฒ๊น
๋ ์ ์ฉํ๋ค๋ ์ฅ์ ์ด ์์ผ๋, ํ์ฌ ์ ํ๋ฆฌ์ผ์ด์
์ ๊ท๋ชจ๊ฐ ํฌ์ง ์๊ณ ๋ฐ์ดํฐ ํ๋ฆ์ด ๋ณต์กํ์ง ์์ ์ฌ๊ธฐ์๋ Context๋ฅผ ์ฌ์ฉํ๊ณ ์ ํ๋ค.
Context๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด ์ฒซ๋ฒ์งธ๋ก ํด์ผํ ์ผ์ Context๋ฅผ ์์ฑํ๋ ๊ฒ์ด๋ค.
import { createContext } from "react"
export const AuthContext = createContext(1)
๊ฐ๋จํ๋ค.
์ด๋ฅผ ๋ค๋ฅธ ์ปดํฌ๋ํธ์์ ์ฌ์ฉํ๋ ค๋ฉด
import React, { useEffect } from "react"
์๋ง ์ด ์ ๋ import ๋์ด์๋ ๊ตฌ๋ฌธ์
import React, { useEffect, useContext } from "react"
import { AuthContext } from "../AutoRefreshToken"
const contextValue = useContext(AuthContext)
์ด ์ ๋ ์ถ๊ฐํด์ ์ฌ์ฉํด์ฃผ๋ฉด ๋๋ค.
์ด๋ฌ๋ฉด ์ด๋์๋ contextValue์ ์ฐ๋ฆฌ๊ฐ ์ค์ ํด์คฌ๋ default ๊ฐ์ธ 1์ด ๋ค์ด๊ฐ๊ณ , ์ด๋ฅผ ์ฌ์ฉํ ์ ์๊ฒ ๋๋ค.
์ฌ๊ธฐ๋ค ์ฐ๋ฆฌ๊ฐ ์์ฑํ axios instance์ธ apiClient๋ฅผ ์ ๋ฌํ๋ ค๋ฉด contetxt๋ฅผ ์ ๊ณต(provide)ํด์ค์ผ ํ๋ค.
import { createContext } from "react"
import axios from "axios"
export const AuthContext = createContext()
export function AuthProvider({ children }) {
const apiClient = axios.create({
baseURL: "https://api.example.com",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${accessToken}`,
},
})
apiClient.interceptors.request.use(
async (config) => {
const expirationTime = new Date(localStorage.getItem("expirationTime"))
if (expirationTime && expirationTime < new Date()) {
const newAccessToken = await refreshToken()
config.headers.Authorization = `Bearer ${newAccessToken}`
localStorage.setItem("accessToken", newAccessToken)
}
return config
},
(error) => {
return Promise.reject(error)
}
)
async function refreshToken() {
const refreshToken = localStorage.getItem("refreshToken")
const response = await axios.post("https://auth.example.com/token", {
grant_type: "refresh_token",
refresh_token: refreshToken,
})
const { access_token } = response.data
const expirationTime = new Date()
expirationTime.setSeconds(
expirationTime.getSeconds() + response.data.expires_in
)
localStorage.setItem("accessToken", access_token)
localStorage.setItem("expirationTime", expirationTime.getTime())
return access_token
}
return (
<AuthContext.Provider value={apiClient}>{children}</AuthContext.Provider>
)
}
์ด๋ฐ์์ผ๋ก AuthProvider๋ฅผ ๋ฐ๋ก ๋ผ์ ์๊ฐ AuthContext.Provider์ ํ์ ์ปดํฌ๋ํธ๋ฅผ ๋ ๋๋งํ๊ฒ ํ๊ณ ,
์ฐ๋ฆฌ๊ฐ ์ฑ์ ๋ ๋๋งํ๋ ๊ณณ(์๋ง๋ App.js)์์ ์ต์์ ์ปดํฌ๋ํธ๋ก <AuthProvider>๋ฅผ ์ง์ด๋ฃ์ด์ฃผ๋ฉด apiClient๋ฅผ ํ์ ์ปดํฌ๋ํธ ์ด๋์๋ ์ฌ์ฉํ ์ ์๊ฒ ๋๋ค.
4. ํ ํฐ ์ฌ๋ฐ๊ธ ์ค ์์ฑ๋ ์์ฒญ์ ๋ํ ์ฒ๋ฆฌ
์ ์์์์๋ ์์ฒญ์ ๋ณด๋ด๊ธฐ ์ ํ ํฐ ๋ง๋ฃ ์๊ฐ์ ํ์ธํด์ ์ฌ๋ฐ๊ธํ์์ผ๋,
์ด๋ฒ์๋ ๋ง๋ฃ๋ ์์ฒญ์ด ๋ณด๋ด์ ธ 401์ด ์๋ต์ผ๋ก ์์ ๋ ์๋ฌ ์ฒ๋ฆฌ๋ก ์ฌ๋ฐ๊ธํ๋ ์์๋ฅผ ๊ฐ์ ธ์๋ค.
apiClient.interceptors.response.use(
(response) => response,
async (error) => {
if (error.response.status === 401) {
const originalConfig = error.config
//error.config.headers.authorizationToken = `Bearer ${newAccessToken}` ์ด๋ ๊ฒ ์ฌ์ฉํ๋ ๊ฒ์ config object๊ฐ immutableํด ๋ถ๊ฐ๋ฅํ๋ค.
if (!isRefreshing) {
isRefreshing = true
try {
const response = await apiClient.post(
`/auth/refresh-token`,
{
refreshToken: refreshToken,
}
)
if (response && response.code === 201) {
accessToken = response.accesstoken
refreshToken = response.refreshtoken
sessionStorage.setItem("accessToken", accessToken)
sessionStorage.setItem("refreshToken", refreshToken)
originalConfig.headers.authorizationToken = `Bearer ${accessToken}`
failedRequests.forEach((f) => f(accessToken))
failedRequests = []
return apiClient.request(originalConfig)
} else {
window.location.href = "/login"
}
} catch (refreshError) {
console.error("Error refreshing access token:", refreshError)
window.location.href = "/login"
throw refreshError
} finally {
isRefreshing = false
}
} else {
const retryOriginalRequest = new Promise((resolve) => {
failedRequests.push((token) => {
originalConfig.headers.authorizationToken = `Bearer ${token}`
resolve(apiClient.request(originalConfig))
})
})
return retryOriginalRequest
}
} else if (error.response.status === 403) {
window.location.href = "/login"
}
}
)
ํ ํฐ ์ฌ๋ฐ๊ธ ์ค ์์ฑ๋ ์์ฒญ์ ๋ํ ์ฒ๋ฆฌ๋ฅผ ์ํด ์ฌ๋ฐ๊ธ์ด ๋๊ณ ์๋ ์ํ๋ฅผ isRefreshing
์ด๋ผ๋ ๋ณ์๋ฅผ ํตํด ์ค์ ํ๋ค.
์ด ์ฒ๋ฆฌ๋ ๋ค์๊ณผ ๊ฐ์ ์ด์ ๋ก ํ์ํ๋ค.
๋ง๋ฃ๋ ํ ํฐ
a
์ ํจ๊ป ๋ณด๋ด์ง ์์ฒญ A๊ฐa'
๋ผ๋ refresh token๊ณผ ํจ๊ป ์ฌ๋ฐ๊ธ๋๋ ์ค, ๋ง๋ฃ๋ ํ ํฐa
๋ก ์์ฒญ B๊ฐ ๋ค์ด์ค๊ณ ์ด๋ฏธ ์ฌ๋ฐ๊ธ ๋ฐ์ ํ ํฐb
,b'
๊ฐ ์์ ๋a'
๋ก ์์ฒญ B๋ฅผ ์ํ ํ ํฐ์ ์ฌ๋ฐ๊ธํ๋ ค๋ฉด ์ด๋ฏธ ์ฌ์ฉ๋ refresh token์ผ๋ก ํ ํฐ ์ฌ๋ฐ๊ธ์ด ๋์ง ์๋๋ค. ๊ทธ๋ผ ๋ค์ 401.. infinite loop์ ๋น ์ง๊ฒ ๋๋ค.
๊ทธ๋์ isRefreshing
์ด true
์ด๋ฉด ๊ทธ๋ ์์ฑ๋ ๋ค๋ฅธ ์์ฒญ๋ค์ ์ฌ๋ฐ๊ธ์ด ์๋ฃ๋๋ฉด ๊ทธ ํ ํฐ๊ณผ ํจ๊ป ์คํํ ์ ์๋๋ก failedRequests array์ Promise๋ก ๋ฃ์ด์ฃผ์ด ํด๊ฒฐํ๋ ค๊ณ ํ๋ค.
์ด ๋ถ๋ถ์ด ๋๋ ์ข ์ด๋ ค์ ์๋๋ฐ, Promise์ ๋ฐฐ์ด ๊ทธ๋ฆฌ๊ณ ์ธ๋ถ ๋ณ์๋ฅผ ์ด๋ป๊ฒ ์กฐํฉํด์ผํ๋์ง๊ฐ ์์ํ๋ค.
์ ๋ต์failedRequests
์ Promise ๊ทธ ์์ฒด๋ฅผ ๋ฃ๋ ๊ฒ์ด ์๋๋ผ, token(์ธ๋ถ ๋ณ์)์ ๋ฐ์ Promise๋ฅผ resolveํ๋ ํจ์๋ฅผ ๋ฃ๋ ๊ฒ์ด์๋ค.
์ ๋ต์ ์ฐพ๊ธฐ ์ ๊น์ง ์ ์ดํด๊ฐ ์๋๋ ๊ฒ ํฌ์ฑ์ด์๋๋ฐ,,, ์ฐพ๊ณ ๋๋ ์ด์ ์ผ Promise๋ฅผ ์ ๋๋ก ์ดํดํ๊ฒ ๋๊ตฌ๋ ์ถ์ด ๋ฟ๋ฏํ๋ค.
๊ทธ๋ฆฌ๊ณ ๊ทธ Promise๋ฅผ return ํด ์๊ฐ failedRequests.forEach((f) => f(accessToken))
๋ฅผ ํตํด resolve๋ ๋ apiClient.request(originlConfig)๋ก ์คํจํ๋ ์์ฒญ์ ๋ค์ ์คํํ๋๋ก ํด์ผ ํ๋ค.
๊ธฐ๋ณธ์ ์ผ๋ก Axios์ interceptors.response ํธ๋ค๋ฌ ํจ์๋ ์์ฒญ์ ๋ํ ์๋ต์ ์ฒ๋ฆฌํ๊ณ Promise๋ฅผ ๋ฐํํ๋ค. ์ด Promise๋ ์๋ต์ ์๋ฃํ๊ณ ํด๋น ์๋ต ๊ฐ์ฒด๋ฅผ ๋ฐํํ๊ฑฐ๋, ์ค๋ฅ๋ฅผ ์ฒ๋ฆฌํ๊ณ ๋ค๋ฅธ Promise๋ฅผ ๋ฐํํ๋ ๋ฐ ์ฌ์ฉ๋๋ค. ์ฌ๊ธฐ์ retryOriginalRequest๋ ์ด์ ์ ์คํจํ ์์ฒญ์ ์ฌ์๋ํ๊ธฐ ์ํ Promise์ด๋ฉฐ ์ด๋ฅผ ๋ฐํํจ์ผ๋ก์จ, ํ์ฌ ์คํจํ ์์ฒญ์ Axios์๊ฒ โ๋ค์ ์๋ํด์ผ ํ๋คโ๊ณ ์๋ ค์ฃผ๋ ๊ฒ์ด๋ค.
5. Fetch ๋ง๊ณ Axios ์ฌ์ฉํ๊ธฐ
์์์ ๊ตฌํํ ๊ฑธ ํ ๋๋ก apiClient๋ฅผ ์ฌ์ฉํด ์์ฒญ์ ๋ณด๋ด์ฃผ๊ธฐ๋ง ํ๋ฉด ๋๋ค.
const getData = () => {
fetch(`${BASE_URL}/data`, {
method: "GET",
headers: {
authorizationToken: `Bearer ${accessToken}`,
},
}).then((resp) => {
if (resp.ok) {
resp.json().then((json) => {
setData(json.data)
}
})
}
์ด๋ฌ๋ ์์ฒญ์
const getData = () => {
apiClient.get(`/data`).then((resp) => {
if (resp.status === 200) {
setData(resp.data)
})
}
์ด๋ ๊ฒ ๋ฐ๊ฟ ์ ์๋ค. ๋ฑ ๋ด๋ ์์ฃผ ๊ฐ๋จํด์ก๋ค.
- JSON ์๋ ํ์ฑ์ผ๋ก resp.json().then((json)=>)์ ๊ณผ์ ์ด ํ์์์ด์ก์ผ๋ฉฐ,
- method: โGETโ์ด ์๋ apiClient.get()์ผ๋ก get์์ ๋ช ์ํ ์ ์๋ค.
- baseURL๊ณผ token์ ์ด์ ๋ authProvider์์ ๊ด๋ฆฌํ๋ฏ๋ก ์ปดํฌ๋ํธ๋ง๋ค BASE_URL์ ๊ฐ์ ธ์ค๊ณ , accessToken์ ๊ฐ์ ธ์ฌ ํ์๊ฐ ์์ด์ก๋ค.
์ด๋ฒ์ PUT ์์ฒญ์ ํ ๋ฒ ์ดํด๋ณด์.
const updateData = (data) => {
fetch(`${BASE_URL}/data`, {
method: "PUT",
headers: {
authorizationToken: `Bearer ${accessToken}`,
},
body: JSON.stringify({
data: data,
}),
})
}
const updateData = (data) => {
apiClient.put(`/data`, {
data: data,
})
}
- body ๋ณด๋ผ ๋ JSON.stringify()๋ ํ์์์ด์ก๋ค.
์ด๋ ๊ฒ ํ ๊ณณ์์ ์ด๊ฒ์ ๊ฒ ๊ด๋ฆฌํ๊ณ ๊ฐ ์ปดํฌ๋ํธ์์ ๊ฐ๋จํ๊ฒ ์์ฒญ๋ณด๋ด๋, fetch๋ฅผ axios๋ก ๋์ฒดํ๊ธฐ ๋ !