현재 SeSAC 교육과정 3차 팀 프로젝트의 마무리 단계여서 해당 프로젝트에서 사용했던 기술들을 정리해보았다. 아직 실력이 부족해서 내가 맞게 설명하고 있는건지는 모르겠지만, 내가 아는 선에서 최대한 쉽게 설명해보려고 한다.
※ 사용언어 - HTML, JS, React, SASS, Bootstrap 등
※ 3차 프로젝트 github repo - https://github.com/treasure-2u/batDream
미세먼지 위젯은 '서울 열린 데이터 광장'에서 제공하는 '서울시 권역별 실시간 대기환경 현황 API'를 통해 데이터를 받아서 제작했다. 해당 위젯 역시 날씨 위젯과 마찬가지로 컴포넌트 제작과정과 디자인 과정으로 나누어 작업을 진행했는데, 여기서는 받아온 데이터의 결과값에 따라 디자인이 다르게 보여지도록 설정한 부분이 있어서 scss 코드에 대한 설명도 하려고 한다.
먼저 제작과정부터 서술하겠다.
컴포넌트 초기 설정
import { useEffect, useState } from 'react';
import '../../styles/weather/Dust.scss';
// 서울시 미세먼지 API
const DUST_API = {
key: process.env.REACT_APP_DUST_API,
base: '',
};
- useEffect, useState를 사용하기 위해 import했다. useEffect는 아래에서 API로 현재 대기환경 정보를 받아오는 함수를 위해 사용될거고, useState는 API를 통해 받아온 데이터들을 정상적으로 출력하기 위해 사용될 예정이다.
- 컴포넌트 제작이 완료되면 디자인을 하기 위해 scss 파일을 import했다.
- API key는 외부에 노출되면 안 되는 값이라서 .env 파일에 저장하여 환경변수로 사용했다.
함수형 컴포넌트 작성 시작 - useState, useEffect 사용
export default function Dust() {
const [error, setError] = useState('');
const [dustGrade, setDustGrade] = useState('');
const [place, setPlace] = useState('');
const [bgClass, setBgClass] = useState('');
useEffect(() => {
getDust();
});
}
- API로 받아온 데이터 중에 내가 출력하고 싶은 것들만 useState로 '현재 상태'와 '앞으로 변화될 상태'를 구조분해할당하여 변수에 저장하고, 초기값은 빈 문자열을 주었다.
- useEffect의 스코프에는 현재 대기환경 정보를 받아오는 함수를 입력하였고, 의존성 배열이 아예 없기 때문에 해당 컴포넌트가 렌더링될 때마다 결과가 다르게 보일 수 있다.
→ 대기환경은 시시각각 변화하기 때문에 빈 배열을 주면 안된다. (빈 배열은 최초 마운트시에만 실행됨!)
JSON 데이터 불러와서 결과에 따라 다른 디자인 출력
const getDust = () => {
let dust_url = `/dust_api/${DUST_API.key}/json/RealtimeCityAir/1/25/`;
fetch(dust_url)
.then((response) => response.json())
.then((data) => {
// 서울시 25개 지역구 중에 강동구만 추출
const gangdongData = data.RealtimeCityAir.row[24];
setPlace(gangdongData.MSRSTE_NM);
setDustGrade(gangdongData.IDEX_NM);
// 미세먼지 정도에 따라 다른 배경색 지정
if (gangdongData.IDEX_NM === '좋음') {
setBgClass('good');
} else if (gangdongData.IDEX_NM === '보통') {
setBgClass('normal');
} else {
setBgClass('bad');
}
})
.catch((error) => setError('ERROR'));
};
- '서울시 권역별 실시간 대기환경 현황 API' 에서 데이터를 불러올 주소를 url이라는 변수에 저장했다.
주소 앞부분의 'dust_url'는 배포 이후에 출력 오류가 생겨 프록시 서버를 설정하면서 작성했다. 프록시 서버와 관련된 부분은 아래에 서술 예정!🙂 주소 끝의 숫자는 데이터의 '요청 시작/종료 위치'를 의미하는데, 이걸 너무 짧게 작성하면 내가 원하는 데이터를 확인할 수 없기 때문에 25개 자치구의 정보를 모두 가져올 수 있도록 1/25로 입력했다. - fetch()를 이용해 JSON 데이터를 불러온다.
현재 서울시 25개 자치구의 정보를 모두 보여주고 있는데, 내가 보여주고 싶은 정보는 하나였어서 점 접근법으로 강동구의 정보만 추출해서 변수에 담았다. 그리고 useState의 setter 함수로 강동구의 정보 중에서도 원하는 부분만 출력될 수 있도록 설정했다. - 앞서 가져온 대기환경 결과가 좋음, 보통, 나쁨으로 표시되므로, if문을 사용하여 "미세먼지 위젯은 신호등처럼 결과에 따라 다른 컬러를 보여주자"고 했던 부분을 반영했다.🚥
- 마지막으로 catch()를 통해, 오류를 잡아내면 'ERROR'라는 메시지를 띄우도록 설정했다.
데이터 출력을 위한 프록시 서버 설정
배포 이후에 위젯의 결과 출력에 오류가 생겨서, 따로 작성했던 프록시 서버 설정이다. Vercel로 배포한 후에, 지역이랑 결과가 전부 안 나오고 'ERROR'만 띄워줘서, 크롬 브라우저 콘솔에 찍힌 메시지를 확인했다.
The page at "https://batdream.vercel.app" was loaded over HTTPS, but requested an insecure resourse "http://~~". This request has been blocked; the content must be served over HTTPS.
배포된 페이지는 https인데, fetch()로 정보를 불러오는 주소는 http로 시작하는 주소여서 보안 문제로 요청이 차단된 것이었다. API 주소를 배포주소 기준으로 변경하고, 프록시 서버와 관련해서는 리더님께 도움을 요청해서 '프록시 미들웨어'를 모듈로 만들어서 내보내는 방식으로 API를 불러와서 사용할 수 있게 작성했다. 프록시 미들웨어의 작동 원리를 chatGPT가 설명해준대로 받아적자면,
// setupProxy.js
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function (app) {
app.use(
'/dust_api',
createProxyMiddleware({
target: 'http://openapi.seoul.go.kr:8088',
changeOrigin: true,
pathRewrite: {
'^/dust_api': '',
},
}),
);
};
- 첫 줄은 프록시 미들웨어를 설정하고, '프록시 미들웨어'라는 어플리케이션을 만들어서 모듈로 내보내겠다는 의미.
- app.use()는 미들웨어를 등록하는 메서드, '/dust_api'로 시작하는 모든 요청에 대해 이 프록시 미들웨어를 사용한다는 뜻.
- createProxyMiddleware() 내부에서 사용할 미들웨어의 세부 설정을 한다.
target은 프록시할 대상 서버의 URL로, 모든 /dust_api 요청은 이 대상 서버로 프록시된다.
changeOrigin은 클라이언트의 요청 주소를 대상 서버의 주소로 변경해주는 속성.
pathRewrite는 요청 경로를 재작성하는 규칙을 정의하여, /dust_api로 시작하는 경로를 빈 문자열로 대체시킨다.
※ '프록시 서버' 관련 개념 정리는 여기 참고 → https://hjinn0813.tistory.com/103
프록시 서버(Proxy Server)의 정의와 사용 이유
SeSAC 수업 당시, 3차 팀플을 진행하면서 Vercel 배포 이후에 내가 제작한 위젯이 제대로 렌더링되지 않아서 '프록시 서버'를 처음 사용했었다. 이름은 익히 들어 알고 있었지만 왜 사용해야 하는지,
hjinn0813.tistory.com
return문 작성하기
return (
<div className={`dust-box ${bgClass}`}>
<div className="dust-info">
오늘의 미세먼지 현황
<br />
<div className="dust-place">{place}</div>
<div className="dust-grade">{dustGrade}</div>
</div>
{error && <div>{error}</div>}
</div>
);
- 화면에 실제로 출력시키기 위해 return문을 작성한다.
- 최상위 태그에 className으로 앞서 작성한 if문 내부 setter 함수의 원래 상태(bgClass)를 props로 연결했고, 화면에는 현재 위치(장소)와 미세먼지 현황(좋음/보통/나쁨)만 보여주도록 했다.
- ERROR는 만약 존재하면 출력되고, 그렇지 않으면 생략되도록 && 연산자를 사용해 작성했다.
scss로 위젯 디자인하기
위젯의 사이즈나 폰트의 굵기 등은 매우 기초적인 내용이라 서술하지 않겠다.
px 단위를 자주 사용했던 이전과 달리, 이번에는 rem 단위로 작성했다는 것 외에는 특별한게 없어서, 결과에 따라 디자인이 다르게 보이도록 설정한 부분에 대해서만 설명하려고 한다.
@import '../root.scss';
.dust-box {
&.good {
background-color: $romain-green;
color: $chiliflower-white;
}
&.normal {
background-color: $chiliflower-white;
border: 1px solid $potato-beige;
}
&.bad {
background-color: $potato-beige;
color: $chiliflower-white;
}
}
- 일단 scss이기 때문에 모든 페이지에서 공통으로 사용되는 디자인을 담아놓은 root.scss가 있어서 사용하기 위해 import했다. 이렇게 하니까 root.scss에서 저장한 변수를 가져와서 사용할 수 있어서 코드가 훨씬 간결해지는 장점이 있었다.👍
- dust-box라는 클래스 선택자에 조건에 따라 다른 배경색과 글자색이 보이도록 지정했다. 우리 팀의 메인 컬러가 그린, 화이트, 베이지인데 공교롭게도 미세먼지 결과 역시 세 가지여서 컬러를 각각 어울리는 결과에 반영시켰다.
이렇게 컴포넌트를 만들고, src/pages/main.jsx에서 해당 컴포넌트를 불러와서 return에 입력하니 정상적으로 화면에 출력되었다. 미세먼지 위젯도 날씨 위젯처럼 메인 페이지에서만 보여지는 요소여서, 다른 배너와 어울리도록 디자인적인 부분을 만졌더니 심플하면서도 기능적인 부분까지 갖춘 위젯이 완성되었다!🙌
'보통'과 '나쁨'을 먼저 캡쳐해놓고 디자인을 수정해서 border-radius가 '좋음'과 다른데, 최종적으로 fix된 디자인은 '좋음'과 같이 더 둥근 border-radius를 사용하고 있다.
💡 미세먼지 위젯 개발 과정에서의 문제와 해결방법
해당 위젯은 원래 '공공데이터포털'에서 제공하는 API를 활용해서 제작할 생각이었다. 하지만 개발 과정에서 구글링을 했을 때, React에서 해당 API를 활용한 사례가 많지 않아서 참고할만한 자료가 없었고, 어렵게 찾은 예시에서는 프록시 서버를 만지는 것 같아보였다. 팀원 중에 이미 프록시 서버 이슈로 고생하는 분이 계시는데 나까지 힘들어하게 되면, 팀 전체의 작업 속도가 느려질 것 같아서 과감하게 포기하고, '서울시 열린 데이터 광장'에서 제공하는 API로 변경했다.
그런데 결론적으로는 앞서 설명한대로, 배포 이후에 출력 오류가 생겨서 프록시 서버 설정을 사용했다..😅
https://data.seoul.go.kr/dataList/OA-2219/S/1/datasetView.do
서울 열린데이터 광장 - 서울시 권역별 실시간 대기환경 현황
대기 환경지수, 미세먼지, 오존, 이산화질소, 일산화탄소, 아황산가스 등의 권역별 실시간 대기환경정보를 제공합니다.
data.seoul.go.kr
여기까지가 미세먼지 위젯에 대한 기술 설명이었다.
이번 프로젝트에서 날씨와 미세먼지 API를 직접 만져보면서 스스로의 부족함을 느꼈고, fetch()로 데이터를 불러와서 다루고 화면에 출력하는 과정을 직접 해보며 '프론트엔드 개발자라도 백엔드 분야에 대한 기초적인 것들은 알고 있어야겠다'는 생각이 들었다. 어느 직업이나 그렇겠지만, 특히 개발자는 정말 끊임없이 공부해야하는 직업 같다.🤔
벌써 종강이 얼마 남지 않았는데, 이번 교육과정이 끝나도 부지런히 배우고 응용하면서, 이제 막 틔운 싹이 나무가 될 수 있도록 해야겠다!🌳

'📁 프로젝트 회고' 카테고리의 다른 글
[코딩온] 프론트엔드 입문 Day 54~55 (3차 프로젝트 7, 발표) (0) | 2024.05.17 |
---|---|
SeSAC 3차 프로젝트 사용 기술 - Not Found 페이지 (0) | 2024.05.11 |
SeSAC 3차 프로젝트 사용 기술 - 날씨 위젯 (0) | 2024.05.11 |
[코딩온] 프론트엔드 입문 Day 52~53 (3차 프로젝트 5~6) (0) | 2024.05.10 |
[코딩온] 프론트엔드 입문 Day 49~51 (3차 프로젝트 2~4) (0) | 2024.05.03 |