Pt. 2) React에 Django 연동하기
파트 1에서는 Django로 JWT 토큰을 이용한 로그인이 동작함을 확인했다. 이제 이것을 프론트엔드와 연결해 보도록 하자.
원래 진행하고 있는 프로젝트에서는 TypeScript로 진행하고 있지만, 튜토리얼 프로젝트에서 굳이 거창하게 TypeScript를 사용할 이유도 없다고 판단했고, TypeScript를 사용할 수 있는 사람은 JavaScript 코드만 봐도 응용할 수 있을 것이라 생각하기 때문에 여기에는 JavaScript 코드로 진행하기로 했다.
React 프론트엔드 프로젝트 설정하기
우리의 친구 CRA를 이용하여 프론트엔드 프로젝트를 설정해 주자. 프로젝트의 최상위 폴더인 auth-tutorial 폴더로 나와서 아래와 같이 입력해 주자.
$ npx create-react-app frontend
혹시라도 CRA가 설치되지 않은 사람들은 npm install -g create-react-app을 이용하여 CRA를 설치 후 진행하면 된다.
이러면 자동으로 frontend 폴더가 생성되고 내부에 React 프로젝트가 생성된다. 그러나 쓸데없는 파일들이 너무 많기 때문에, src 폴더의 내부에 App.js와 index.js를 제외한 나머지 파일을 전부 삭제하고, App.js와 index.js 에서도 삭제한 파일에 대한 import를 전부 삭제해주도록 하자.
App.js
import React from "react";
const App = () => {
return <div className="App">Hello world!</div>;
}
export default App;
index.js
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
function 대신 화살표로 표현하는 게 습관이 들어서 앞으로 작성할 코드와의 통일성을 위해 export const function App...을 화살표로 작성했고, 똑같이 내 습관 때문에 아래에 따로 export default를 해 줬다. export const function App은 그대로 놔둬도 상관 없다.
로그인 페이지 생성하기
이제 폼을 생성해서 로그인을 입력받도록 하자. 그러나 로그인 페이지를 만드는 것은 이 프로젝트의 내용이 아니기 때문에, 적당한 템플릿을 긁어 오고자 한다. MUI에서는 무료 React 템플릿을 제공하고 있다. 우리가 사용할 것은 Sign In 템플릿이다.
위 링크에 있는 소스 코드를 갖다 쓰도록 하자. 나는 해당 내용을 frontend/src/pages/login/index.js에 붙여 넣었다. 템플릿 이름이나 내부 내용은 sign in으로 되어 있지만 백엔드와의 통일성을 위해 이름으로는 login을 선택했다. 그리고 App.js에서 위 파일을 import하도록 하자.
App.js
import React from "react";
import SignIn from "./pages/login";
const App = () => {
return (
<div className="App">
<SignIn />
</div>
);
}
export default App;
그리고 npm start를 통해 확인해 보면…당연히 오류가 난다. MUI를 통한 페이지를 불러왔기 때문에 MUI에 관련된 패키지를 설치해 주어야 한다. frontend 폴더로 들어가 아래와 같이 실행하도록 하자.
$ cd frontend
$ npm install @mui/material @mui/icons-material @emotion/react @emotion/styled
위와 같이 필요한 패키지를 전부 설치한 후 다시 npm start로 확인해 보면,
해당 이미지처럼 별다른 노력 없이도 볼만한 로그인 페이지가 만들어졌음을 확인할 수 있다.
Django의 API와 연결하기
이제 페이지도 만들었으니 백엔드와 연결해주도록 하자. 먼저, REST 통신을 위해 axios를 설치하자. fetch 명령어로도 실행할 수 있지만 역시 내 습관 때문에 나는 axios를 이용하는 것이 편해서 axios로 진행하려 한다.
$ npm install axios
axios는 위 명령어로 설치할 수 있다. axios를 설치했다면, 로그인 페이지에 프론트엔드 로직을 작성해 보자.
먼저, SignIn 함수 내부의 handleSubmit을 지우고, handleSubmit이 연결된 컴포넌트에서도 연결을 해제하도록 하자. onSubmit={handleSubmit}을 찾아서 지워 주면 된다.
그리고, 아래와 같이 작성해주자.
import React, { useState } from "react"; // import * as React from "react"를 수정함!
...
import axios from "axios";
...
위는 import 문이 있는 최상단에,
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const data = { username: username, password: password };
const handleSubmit = (e) => {
e.preventDefault();
axios
.post("http://localhost:8000/user/login", data)
.then(({ data }) => console.log(data));
};
위는 SignIn 함수의 맨 위에 작성해 준다.
<Box
...
component="form"
onSubmit={handleSubmit}
>
<TextField
...
id="email"
value={username}
onChange={(e) => setUsername(e.target.value)}
/>
<TextField
...
id="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
...
</Box>
그리고 form과 input에 위와 같이 value와 event handler를 연결해 주자. 그리고 실행해보면…
당연하게도 CORS 에러가 난다. 분명 Django에서 django-cors-headers를 이용해서 처리해줬는데 왜 이런지는 잘 모르겠다(왜 이러는지 아시는 분이 계시다면 댓글 부탁드립니다). 프론트엔드에서도 처리해줘야 하나보다.
CORS 해결하기
프론트엔드에서 CORS 문제를 해결해 주는 것은 간단하다. src 폴더 안에 setupProxy.js(TypeScript로 작업하는 사람도 이 파일은 .js로 만들어야 한다)를 생성해서 아래와 같이 작성하면 된다.
const { createProxyMiddleware } = require("http-proxy-middleware");
module.exports = function (app) {
app.use(
["/api", "/user"],
createProxyMiddleware({
target: "http://localhost:8000",
changeOrigin: true,
})
);
};
app.use의 첫번째 parameter로는 request를 보내고자 하는 url들이 담겨 있고, createProxyMiddleware를 통해 우회 설정을 하고자 하는 주소를 설정해주면 된다.
또, axios를 통한 request의 주소를 살짝 수정해 주자.
const handleSubmit = (e) => {
e.preventDefault();
axios.post("/user/login/", data).then(({ data }) => console.log(data));
};
모든 주소를 작성하지 않고 /user부터 작성하고, 마지막은 꼭 ‘/’(슬래시)로 마무리해 주도록 하는 것을 잊지 말자. setupProxy.js는 npm start를 처음 실행할 때에만 불러오기 때문에 한번 중지했다가 다시 실행하도록 하자.
테스트
이제 진짜로 모든 준비가 끝났다. 백엔드 서버까지 실행시킨 후에 폼에 username과 password를 입력한 후 SIGN IN 버튼을 누르면…
드디어 response를 받았음을 확인할 수 있다. access token과 refresh token은 물론, Django에서 추가해 준 success 여부와 username까지 성공적으로 받았다.
마치며
사실 JWT를 구현했다고 하기엔 말하기 애매한 게, 토큰을 받아서 클라이언트인 프론트 환경에서 받아오는 것까지 성공했지만 아직 이걸론 브라우저에 로그인 정보고 뭐고 아무것도 저장된 게 없다. 하지만 여기까지 구현하는 것도 나한테 있어서도 처음 경험해보는 작업임에도 불구하고 성공적으로 토큰을 받아올 수 있다는 점에 의의를 두려고 한다.
이후에는 클라이언트에 토큰을 저장하는 것과 토큰 갱신/검증이다.
'공부 > React' 카테고리의 다른 글
React에서 map() 사용 시 key 값에 대하여 (0) | 2022.09.28 |
---|