Skip to content

7주차 고다경 과제구현#5

Open
onegood07 wants to merge 8 commits intoTEAM-ALOM:mainfrom
onegood07:main
Open

7주차 고다경 과제구현#5
onegood07 wants to merge 8 commits intoTEAM-ALOM:mainfrom
onegood07:main

Conversation

@onegood07
Copy link
Copy Markdown

📍 BackGround

  • 세종대학교 아롬 동아리의 리액트 스터디 7주차 과제 - <날씨 API 활용>구현

😎 Content

파일 구조

  • 최종 파일 구조는 아래와 같음
📦src
 ┣ 📂components
 ┃ ┣ 📂styles
 ┃ ┃ ┗ 📜StyledComponents.js
 ┃ ┣ 📜CurrentWeather.js
 ┃ ┣ 📜DailyForecast.js
 ┃ ┗ 📜HourlyForecast.js
 ┣ 📂constants
 ┃ ┣ 📜exampleResponse.js
 ┃ ┗ 📜uiConstants.js
 ┣ 📂utils
 ┃ ┣ 📜validators.js
 ┃ ┣ 📜weather.js
 ┃ ┗ 📜weeks.js
 ┣ 📜App.css
 ┣ 📜App.js
 ┣ 📜index.css
 ┣ 📜index.js
 ┗ 📜logo.svg

styled-components

  • 저번 스터디에서 처음 보았던 방식인데, 이번에 직접 사용해보니 매우 편리하고 태그에서 보기 편하다는 걸 알게됨!
// 미리 작성된 예시
import styled from "styled-components";

export const Container = styled.div`
  min-height: 100vh;
  background: linear-gradient(to bottom, #87ceeb, #4682b4);
  padding: 20px;
`;

함수

  • timeString과 hour를 분리하여 map으로 돌릴 때 key값으로 부여함
  • index를 활용하여 최대한 한번에 처리하는 것이 목표였음
  • 현재 format 함수에서 아예 보여질 값까지 처리해서 반환하고 있는데, 분리해서 필요한 json 부분만 받아와서 객체로 만들어두기 -> format하기로 나누는 것이 훨씬 좋을거라는 생각이 들었음.
// weather.js
export const formatHourlyData = (weatherData) => {
  if (!weatherData) return [];
  const currentDate = new Date();
  const result = [];

  weatherData.hourly.time.forEach((time, index) => {
    const hourlyDate = new Date(time);

    if (
      isToDay(hourlyDate, currentDate) &&
      isWithin12Hours(hourlyDate, currentDate) &&
      result.length < 12
    ) {
      result.push({
        timeString: hourlyDate.toISOString(),
        hour: hourlyDate.getHours(),
        temperature: Math.floor(weatherData.hourly.temperature_2m[index]),
        weatherCode: weatherData.hourly.weather_code[index],
      });
    }
  });

  return result;
};

export const formatDailyData = (weatherData) => {
  if (!weatherData) return [];

  const result = weatherData.daily.time.map((time, index) => {
    const dailyDate = new Date(time);

    return {
      timeString: dailyDate.toISOString(),
      date: `${dailyDate.getMonth() + 1}월 ${dailyDate.getDate()}일 (${getWeekdayName(
        dailyDate.getDay()
      )})`,
      temperature: Math.floor(weatherData.daily.temperature_2m_max[index]),
      weatherCode: weatherData.daily.weather_code[index],
    };
  });

  return result;
};

📸 Screenshot

스크린샷 2025-05-18 오후 1 48 26

Copy link
Copy Markdown

@greetings1012 greetings1012 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

수고하셨습니다! 코드를 잘 작성해주셔서 이전보다 리뷰 달 내용이 많지 않네요!
몇 개 생각할 거리를 적어 놨으니, 확인 후 Reply 부탁드립니다!

Comment thread src/components/CurrentWeather.js Outdated

if (isLoading) {
return <div>채워주세요</div>;
return <div>{LOADING}</div>;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Loading 대신 스피너나 간단한 스켈레톤 UI를 추가해보는 것도 좋을 것 같아요!

https://blog.makerjun.com/2f7a9818-df45-4eab-9768-b79d61b4d0ec

Copy link
Copy Markdown
Author

@onegood07 onegood07 May 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

import { SpinnerWrapper } from "./styles/StyledComponents";
import { ClockLoader } from "react-spinners";

const Spinner = () => {
  return (
    <SpinnerWrapper>
      <ClockLoader color="white" size={150} />
    </SpinnerWrapper>
  );
};

export default Spinner;

찾아보니 스피너 라이브러리가 있어서 사용해보았습니다!

참고자료
https://www.davidhu.io/react-spinners/

https://choijying21.tistory.com/entry/%EB%A6%AC%EC%95%A1%ED%8A%B8-%EB%A1%9C%EB%94%A9%ED%99%94%EB%A9%B4-%EC%8A%A4%ED%94%BC%EB%84%88-%EB%A7%8C%EB%93%9C%EB%8A%94-%EC%97%AC%EB%9F%AC%EA%B0%80%EC%A7%80-%EB%B0%A9%EB%B2%95gif-React-spinners

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Comment thread src/utils/validators.js Outdated
@@ -0,0 +1,23 @@
export const isToDay = (dateInData, currentDate) => {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
export const isToDay = (dateInData, currentDate) => {
export const isToday = (dateInData, currentDate) => {

Comment thread src/utils/validators.js
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

데이터 검증 로직 좋습니다 😁

Comment thread src/utils/weather.js Outdated
import { getWeekdayName } from "./weeks";

export const getWeatherDescription = (code) => {
const weatherCodes = {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

여기도 constants.js로 분리하면 어떨까요?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

constants로 분리 후, 아래와 같이 변경했습니다!

// weather.js
export const getWeatherDescription = (code) => {
  return WEATHER_CODE[code] || "알 수 없음";
};

Comment thread src/utils/weather.js Outdated
};

export const formatCurrentData = (weatherData) => {
if (!weatherData) return;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

만약 문제가 발생해서 return했다면 console에 log라도 찍어주면 개발할 때 빠르게 어느 부분에서 문제가 생겼는지 확인할 수 있을 것 같아요!

Copy link
Copy Markdown
Author

@onegood07 onegood07 May 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// logger.js
export const errorLog = (component, message) => {
  console.log(`[${component}] ${message}`);
};

// weather.js
export const formatCurrentData = (weatherData) => {
if (!weatherData) {
    errorLog(formatCurrentData.name, FAILED_LOAD_DATA);
    return;
  }
}

다음과 같이 작성했습니다!

Comment thread src/utils/weather.js Outdated
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

전체적으로 안에 포매팅 기능을 하는 부분들이 많은데, 이를 별도의 util 함수로 분리하면 좋겠습니다!

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// weather.js -> fetchWeatherData.js
export const fetchCurrentData = (weatherData) => {
  if (!weatherData) {
    errorLog(fetchCurrentData.name, FAILED_LOAD_DATA);
    return;
  }

  const index = weatherData.hourly.time.findIndex((time) => isInCurrentTime(new Date(time)));

  return {
    time: new Date(weatherData.hourly.time[index]),
    temperature: weatherData.hourly.temperature_2m[index],
    weatherCode: weatherData.hourly.weather_code[index],
  };
};

fetch로 시작하는 함수들로 변경하여 최대한 데이터 원본 형태로 불러오도록 수정했습니다.

Comment thread src/utils/weather.js Outdated
Comment on lines +46 to +49
if (
isToDay(hourlyDate, currentDate) &&
isWithin12Hours(hourlyDate, currentDate) &&
result.length < 12
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이것도 validate 로직이니까 따로 분리하면 좋을 것 같네요!

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// validators.js
export const isValidHourlyData = (hourlyDate, currentDate, collectedForecasts) => {
  return (
    isToday(hourlyDate, currentDate) &&
    isWithin12Hours(hourlyDate, currentDate) &&
    collectedForecasts.length < 12
  );
};

기존에 result였던 배열명도 collectedForecasts로 변경하고 validators 안에 분리했습니다!

Comment thread src/utils/weather.js Outdated
Comment on lines +52 to +55
timeString: hourlyDate.toISOString(),
hour: hourlyDate.getHours(),
temperature: Math.floor(weatherData.hourly.temperature_2m[index]),
weatherCode: weatherData.hourly.weather_code[index],
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

포매팅 함수도 분리해 봅시다!

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// formatWeatherData.js
export const formatHourlyData = (weatherData) => {
  if (!weatherData) {
    errorLog(formatHourlyData.name, FAILED_LOAD_DATA);
    return null;
  }

  return weatherData.map(({ time, temperature, weatherCode }) => {
    const date = new Date(time);
    return {
      time: date.toISOString(),
      hour: date.getHours(),
      temperature: Math.floor(temperature),
      weatherCode: getWeatherDescription(weatherCode),
    };
  });
};
  • fetchWeatherData.js와 formatWeatherData.js로 분리했습니다~

Comment thread src/utils/weather.js Outdated
Comment on lines +70 to +75
timeString: dailyDate.toISOString(),
date: `${dailyDate.getMonth() + 1}월 ${dailyDate.getDate()}일 (${getWeekdayName(
dailyDate.getDay()
)})`,
temperature: Math.floor(weatherData.daily.temperature_2m_max[index]),
weatherCode: weatherData.daily.weather_code[index],
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

포매팅!

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// formatWeatherData.js
export const formatDailyData = (weatherData) => {
  if (!weatherData) {
    errorLog(formatDailyData.name, FAILED_LOAD_DATA);
    return null;
  }

  return weatherData.map(({ time, temperature, weatherCode }) => {
    const date = new Date(time);

    return {
      time: date.toISOString(),
      date: `${date.getMonth() + 1}월 ${date.getDate()}일 (${getWeekdayDescription(
        date.getDay()
      )})`,
      temperature: Math.floor(temperature),
      weatherCode: getWeatherDescription(weatherCode),
    };
  });
};
  • fetchWeatherData.js와 formatWeatherData.js로 분리하여 포매팅했습니다!

Copy link
Copy Markdown

@greetings1012 greetings1012 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

수고하셨습니다!
전체적으로 파일 및 기능 분리에 대해 피드백 드렸는데, 잘 해내어 주셨네요!
다음 미션도 화이팅입니다 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants