카테고리 없음

개인 프로젝트 - 날씨 앱 (4) 추천 옷/ 음악 공통 컴포넌트 만들기, 날씨에 맞는 배경 컴포넌트

creamymood 2025. 6. 3. 17:15

 


해당 게시글에서의 구현 목표는

디테일 페이지에서 온도에 따른 추천 옷과 노래를 보여주고,

날씨에 맞는 배경을 보여준다.

1) 한 공통 컴포넌트에서 온도별로 나눈다.

공통 컴포넌트를 만든 뒤, 그 안에서 온도 분기 처리 해줄 예정

 

 

 

1. 우선 Clothes 공통 컴포넌트에 온도를 props로 내려준다.

 

불필요한 코드를 제거한 코드는 다음과 같다.

 return(
            <div>
                { detailCityWeatherValue? (
                     <>
                     <Clothes temp={Math.trunc(detailCityWeatherValue.main.temp)}/>
                	 </>
                ):(
                    <p>날씨 정보를 불러오는 중...</p>
                )}
            </div>
        )

 

 

 

2. Clothes 공통 컴포넌트에서 if문으로 온도 분기 해주고 그에 맞는 멘트를 만들어준다.

import React from "react";

function Clothes ({temp}) {

    let clothesText = ""

    if(temp < 0) {
        clothesText = "패딩과 목도리를 입으세요!";
    }else if(temp <=10) {
        clothesText = "코트를 추천 합니다!";
    }else if(temp <= 20) {
        clothesText = "간단한 가디건을 걸치세요";
    }else {
        clothesText = "반팔 또는 민소매도 충분 합니다!";
    }
    
return (

    <div>
        {
          <p>오늘의 온도는 {temp}도 입니다. {clothesText} </p>
        }

    </div>
)


}

export default Clothes

 

 

이렇게 의류는 추천이 끝!

 

 

3. 추천 노래 객체를 만들고 랜덤으로 생성하는 함수를 만든 뒤, UI에 그려준다.

 

 const songs = {
        cold: ["December 25th - Charlie Puth", "Heroin - back number", "BLUE - 3House", "first snow - AYANE"],
        mildCold: ["Autumn Leaves - Ed Sheeran", "September- Earth, Wind & Fire", "Like that- Keshi", "LANY - somewhere"],
        warm: ["love. -wave to earth", "LANY - Alonica", "LANY - Out of my League"],
        hot: ["LANY - Cowboy in LA", "Hot summer - f(x)", "West Coast Weekend - Tyga", "Attention - New Jeans"] 
    }

이런식으로 추천 노래 객체를 만들어줬다.

 

그 뒤, 해당 배열에서 무작위로 랜덤으로 노래를 반환해주는 함수를 만들어주는데

 function recommendSongs(songs) {
      const index = Math.floor(Math.random()* songs.length)
        return songs[index]
    }

그 함수는 다음과 같다.

 

math.random 매서드로 랜덤 숫자 생성 -> 그걸 인덱스 번호라고 생각해주고, 그걸 -> songs[index]는 그 숫자를 배열의 위치로 해석해서 그 자리에 있는 값을 반환하는 것

 

랜덤 함수 코드 설명은 다음과 같고,

더보기
const index = Math.floor(Math.random() * list.length);

 

  • Math.random()은 0 이상 1 미만의 소수점 랜덤 숫자를 만든다. 예를 들어 0.234, 0.876 같은 숫자.
  • list.length는 리스트의 길이, 즉 배열에 들어있는 요소(노래) 개수를 의미.
  • 그래서 Math.random() * list.length는 0부터 list.length 미만까지의 소수를 만듬.
  • Math.floor()는 소수점 아래를 버리고 내림을 해서 정수로 바꿔줌. 예를 들어 3.8 → 3, 0.9 → 0.
  • 이 전체 코드는 배열의 인덱스 번호(0부터 시작하는 정수)를 랜덤으로 하나 뽑는 거야.

 

주의 할 점은 다음과 같다.

더보기

위에 index부분은 그냥 랜덤 숫자를 만들어주는 것 뿐이고, 

 ✨ 여기가 아주 핵심이다 ✨

return songs[index];

리턴 하는 부분에서 배열 꺼낼 때 [] 이렇게 꺼내야 하는 것.

랜덤으로 만들어진 숫자를 저기에 넣음으로써, 그 자리에 해당하는 값을 꺼내는 것!

 

배열에서 songs[index]가 의미하는 것

[] (대괄호)를 **"배열 접근 연산자"**라고 부르는데,
이건 자바스크립트 문법에서 배열 안에 있는 특정 위치(인덱스)에 있는 값을 꺼내는 방법.


자바스크립트 문법으로 본 배열 접근

const songs = ['a', 'b', 'c', 'd'];  // 배열 예시
console.log(songs[0]);  // 'a' 출력, 배열 첫 번째 요소
console.log(songs[2]);  // 'c' 출력, 배열 세 번째 요소

여기서:

  • songs는 배열 변수고
  • songs[숫자] 는 그 배열의 숫자 번째 위치에 있는 값을 뜻해.

songs[index] 가 배열 위치로 해석되는 이유

  • 자바스크립트 문법상 [] 안에 숫자를 넣으면
    → 그 숫자를 **배열의 위치(인덱스)**로 보고, 해당 위치에 있는 값을 반환해.
  • 즉,
songs[3]

이면 배열 songs의 4번째 요소를 의미하는 것


예를 들어보면

const songs = ['song1', 'song2', 'song3', 'song4'];
const index = 2;
console.log(songs[index]); // 'song3' 출력됨

index가 2니까, songs[2]는 세 번째 요소인 'song3'를 가져오는 것


다시 정리하자면

  • 배열명 뒤에 []를 쓰면 → 안에 들어가는 숫자를 배열에서 꺼낼 위치로 '자동 해석' 해준다.
  • index는 그 숫자를 담은 변수일 뿐이고
  • 결국 songs[index]는 songs 배열의 index 위치에 있는 값을 의미함.

 

전체 코드

더보기
import React from "react";

function Clothes ({temp}) {

    let clothesText = ""
    let song = ""

    const songs = {
        cold: ["December 25th - Charlie Puth", "Heroin - back number", "BLUE - 3House", "first snow - AYANE"],
        mildCold: ["Autumn Leaves - Ed Sheeran", "September- Earth, Wind & Fire", "Like that- Keshi", "LANY - somewhere"],
        warm: ["love. -wave to earth", "LANY - Alonica", "LANY - Out of my League"],
        hot: ["LANY - Cowboy in LA", "Hot summer - f(x)", "West Coast Weekend - Tyga", "Attention - New Jeans"] 
    }

   function recommendSongs(songs) {
        const index = Math.floor(Math.random * songs.length)
        return songs[index]
   }

    if(temp < 0) {
        clothesText = "패딩과 목도리를 입으세요!";
        song = recommendSongs(songs.cold);

    }else if(temp <=10) {
        clothesText = "코트를 추천 합니다!";
        song = recommendSongs(songs.mildCold);

    }else if(temp <= 20) {
        clothesText = "간단한 가디건을 걸치세요";
        song = recommendSongs(songs.warm);

    }else {
        clothesText = "반팔 또는 민소매도 충분 합니다!";
        song = recommendSongs(songs.hot);

    }
    
return (

    <div>
        {
           <>
          <p>오늘의 온도는 {temp}도 입니다. {clothesText} </p>
          <p>지금 온도에 맞는 추천 노래는?! {song} </p>
          </>
        }

    </div>
)


}

export default Clothes

 

 

여기서 songs와 clothesText를 초기에 "" 빈 문자열로 지정해두는 이유?

초기값을 빈 문자열로 지정하는 이유는 예방 차원에서 미리 변수의 타입과 기본값을 명확히 설정하기 위해서다.

이렇게 간단한 추천 노래도 뜬다!

 


2. 배경 컴포넌트를 만든다

배경이랑 옷 추천이랑 사실 같은 컴포넌트에서 구성 할 수는 있다. 온도에 따라 설정한다면..

하지만 보여지는 배경은 온도보다는, 날씨에 따라 보여주는 것이 조금 더 적절한 것 같다.

 

그랬을 때..

생각해본 아이디어 흐름은 다음과 같다.

더보기

날씨에 따라 배경을 조건부 렌더링 해주려면

우선 날씨가 어떤 것이 있는지 확인 하고, 그 범주를 나눠야 한다고 생각했고

지금 받아오고 있는 API의 정보를 확인 해봤을 때.. main.description 데이터를 사용하고 있으니까,

우선 OpenWeather사이트에서 어떤 종류의 날씨가 있을까.. 하고 찾아봤다.

하지만 정확한 정보가 나오지 않아서, 구글링도 했는데.. 전체 종류의 날씨는 나오지 않아서 gpt에게 물어봤음

 

openWeather사이트나 구글링해봐도, 제공하는 전체 종류의 날씨는 정보가 안나오네,, 그거에 따라 매핑 해주려고 하는데.

 

Clear 맑음
Clouds 구름 많음
Rain
Drizzle 이슬비
Thunderstorm 천둥번개
Snow
Mist 옅은 안개
Smoke 연기
Haze 연무
Dust 먼지
Fog 짙은 안개
Sand 모래
Ash 화산재
Squall 돌풍
Tornado 토네이도

 

이런 메인 날씨 종류가 있는 듯 했다. 우선 크게 맑음 / 비 / 눈 / 흐림
이렇게만 처리 해주고자 했음

 

맑음에 clear. 

비에 rain, drizzle, Thunderstorm, Tornado

눈에 snow

흐림에 Clouds, Mist, Smoke, Haze, Dust, Fog, Sand, Ash, Squll 이렇게 4그룹으로.

 

이렇게 그룹을 나눴고, 배경이 될 이미지를 준비하고 나니,

이미지를 어떻게 배경으로 처리하지 ? 생각이 들었다. CSS도 조건부 렌더링이 가능했나?


→ 최종적으로 인라인 스타일로 배경 처리 해주기로 결정

 

1) 사용될 이미지를 리액트 프로젝트에 저장해줬고

2) background 컴포넌트를 만들어서

3) 날씨를 props로 전달 받아

4) 전달받은 날씨에 따라 배경을 달리 switch로 보여주는 것 

5) background 컴포넌트를 home.jsx에서, 감싸주기

 

 

 

3) 날씨를 props로 전달해줬다. (main 정보)

 <Backgrounds weather={weather.weather[0].main}/>

물론 이것도 weather의 값이 있을 때만 보여야 하니까, weather ? 이 안에 넣어줬음

 

4) background 컴포넌트에서, 날씨에 따라 switch로 보여줌

날씨 4그룹에 나뉘어서 저렇게 4개의 이미지를 보여주는 형식

import React from "react";
import sunny from "../assets/images/sunny.jpg"
import cloudy from "../assets/images/cloudy.jpg"
import rainy from "../assets/images/rainy.jpg"
import snow from "../assets/images/snow.jpg"





function Backgrounds ({weather, children}) {
    const backgroundImage = () => {
        switch(weather) {
            case `Clear`:
                return sunny;
            case `Rain`:
            case `Drizzle`:
            case `Thunderstorm`:
            case `Tornado`:
                return rainy;
            case `Snow`:
                return snow;
            case `Clouds`:
            case `Mist`:
            case `Smoke`:
            case `Haze`:
            case `Dust`:
            case `Fog`:
            case `Sand`:
            case `Ash`:
            case `Squll`:
                return cloudy;
            
            default:
                return sunny;

        }
    }
    const style = {
        backgroundImage: `url(${backgroundImage()})`,
        backgroundSize: 'cover',
        backgroundPosition: 'center',
        backgroundRepeat: 'no-repeat',
        width: '100vw',
        height: '100vh',
        position: 'relative',
        display: 'flex',
        justifyContent: 'center',
        alignItems: 'center',
        color: 'white',
        fontSize: '2rem',
        textShadow: '0 2px 6px rgba(0, 0, 0, 0.6)',
      };
    
      // 반투명 오버레이는 스타일로 표현
      const overlayStyle = {
        position: 'absolute',
        top: 0,
        left: 0,
        width: '100%',
        height: '100%',
        backgroundColor: 'rgba(0, 0, 0, 0.4)', // 검정 필터
        zIndex: 1,
      };
    
      const contentStyle = {
        position: 'relative',
        zIndex: 2,
      };
    

    return(
        <div style={style}>
        <div style={overlayStyle}></div>
        <div style={contentStyle}>
          {children}
        </div>
      </div>
    );
    


}


export default Backgrounds

css는 지피티가 짜줬다..

 

해당 background 컴포넌트를 home페이지와 detail 페이지에서 불러와주니

home.jsx

 

Detail.jsx

이렇게 잘 뜨는것을 확인 할 수 있다.

현재 도쿄는 비가 오고 있고, 그에 맞춰 배경이 바뀌었고, 추천 옷이나 노래가 뜨는 것도 확인 가능하다.

 

우선 이렇게 배경 컴포넌트 까지 적용을 했는데..

css가 정말 엉망이라,, 지피티한테 조금 부탁해서 손봐야 할 것 같다!

기능 구현은 완성:)


<심화 공부>

1. 추천 음악은 유튜브 재생까지?

2. 애니메이션 효과 (배경 전환 시 페이드인/아웃 애니메이션을 넣으면) 

3. 이미지 외에도 gradient나 filter 추가 고려

  • 밤/낮 시간대에 따라 dark overlay, sunrise filter 등을 넣으면 더 몰입감

 보너스 아이디어

  • 시간대 기반 배경 추가 (낮/밤 이미지)
  • 날씨 + 시간 조합 → 예: 밤 + 비 = 어두운 흐림 이미지
  • 배경 영상 사용 (무거우면 optional)
  • 로딩 중 기본 배경 설정

<심화 아이디어 공부>

아직은 너무 어려운 알고리즘. 이 부분은 그냥 이런게 있다고 알고 넘어가보는 정도로 

더보기

와 근데 경우의 수 알고리즘은 어떻게 짤까..

 

예를 들어 10도야. 그 때 비가 와. 그럴 때는 ?

 

약간 현재 온도는 20도로 따뜻한 편입니다. 하지만 비가 와서 춥습니다! 겉옷을 챙기세요!

 

이렇게 세세하게 또 나누는걸 어떻게 하지 인공지능 미틴거같아....

근데 엄청 어렵진 않은 것 같아서 적용해볼 수 있을 것 같다..

더보기

Jane 진짜 감탄하는 포인트 너무 공감돼 ㅋㅋㅋㅋ
맞아! 날씨 앱에서 “온도 + 날씨 상황(비, 눈, 흐림 등)” 조합까지 고려하는 건 한 단계 더 나아간 거고,

이걸 “경우의 수 알고리즘”이라고 부를 수도 있어.

이걸 구현하는 핵심은 **"조건을 조합해서 처리하는 로직"**을 잘 짜는 거야.


 예시 목표

현재 온도는 20도
날씨는 비(Rain)
→ “20도라 따뜻한 편이지만 비가 와서 겉옷을 챙기세요!”


 

우선 기본적인 날씨 데이터를 아래처럼 있다고 가정해보자:

const weatherData = {
  temp: 20,
  condition: "Rain",  // Clear, Rain, Snow, Clouds 등
};

조건 조합 알고리즘 예시

function getClothingSuggestion(temp, condition) {
  let baseText = "";
  let extraText = "";

  // 온도 기준 문장
  if (temp <= 0) {
    baseText = "날씨가 매우 춥습니다.";
  } else if (temp <= 10) {
    baseText = "쌀쌀한 날씨입니다.";
  } else if (temp <= 20) {
    baseText = "선선한 날씨입니다.";
  } else {
    baseText = "따뜻한 날씨입니다.";
  }

  // 날씨 상황 추가 설명
  if (condition === "Rain") {
    extraText = "하지만 비가 오니 겉옷과 우산을 챙기세요!";
  } else if (condition === "Snow") {
    extraText = "눈이 오니 따뜻하게 입고 조심히 다니세요!";
  } else if (condition === "Clouds") {
    extraText = "구름이 많아 약간 쌀쌀할 수 있어요.";
  } else {
    extraText = ""; // 맑은 날 등 특별한 설명 X
  }

  return `${baseText} ${extraText}`;
}

사용 예:

const suggestion = getClothingSuggestion(weatherData.temp, weatherData.condition);

return (
  <div>
    <p>{suggestion}</p>
  </div>
);

 

 

이런 것도 가능해:

  • 온도 + 날씨 + 바람세기 + 체감온도까지 계산해서
    “현재 기온은 20도지만, 강풍 때문에 체감온도는 15도예요.”
  • 그리고 예를 들어 불쾌지수, 미세먼지, 자외선 지수까지 넣어서 추천 콘텐츠를 바꿔줄 수도 있어요.

 정리: 경우의 수 알고리즘은 어떻게 짜냐?

  1. **기본 기준 (온도 등급)**을 먼저 분리
  2. **보조 조건 (비/눈/흐림 등)**을 조합
  3. 조건문(if, switch, &&, ||)으로 조합
  4. 각각 조합에 맞는 문장을 구성