[DAY - 102] #11 개인프로젝트 '오늘 하날'

2023. 7. 27. 22:15·🔥 부트캠프-웹 개발 🔥/오늘하날(개인프로젝트)

오늘은 어제 테스트했던 현재 위치, 날씨를 작업 중인 프로젝트에 이식했다.

 

1) 현재 위치

 

현재 위치가 적용되어야 할 부분은 업로드, 내주변, 궁금해요 총 세 곳이다.

먼저 어제와 마찬가지로 hook을 만들었다.

 

import { useEffect, useState } from "react";
import axios from "axios";
import { useDispatch } from "react-redux";
import { getLocation } from "../store/modules/acountSlice";

const useLocationHook = () => {
    const dispatch = useDispatch()
    const [address, setAddress] = useState('');
    const [location, setLocation] = useState({
        latitude: 0,
        longitude: 0,
        nowLocationCity: '',
        nowLocationGu: '',
        error: null,
    });
    const loading = {
        latitude: 0,
        longitude: 0,
        nowLocationCity: '현재위치',
        nowLocationGu: '조회중',
        error: null,
    }

    useEffect(() => {
        if (navigator.geolocation) {
            navigator.geolocation.getCurrentPosition(success, error);
        } else {
            setLocation({
                ...location,
                error: '현재위치 기능을 지원하지 않는 브라우저입니다.',
            });
        }
    }, []);

    const success = (position) => {
        const { latitude, longitude } = position.coords;
        getKakaoAddress(latitude, longitude);
    };

    const error = (err) => {
        setLocation({
            ...location,
            error: '현재위치를 가져올 수 없습니다.',
        });
    };

    const getKakaoAddress = async (latitude, longitude) => {
        const kakaoApiKey = 'apikey';
        try {
            const response = await axios.get(`https://dapi.kakao.com/v2/local/geo/coord2regioncode.json?x=${longitude}&y=${latitude}`, {
                headers: {
                    Authorization: `KakaoAK ${kakaoApiKey}`,
                },
            });
            const data = response.data;
            const nowLocationCity = data.documents.length > 0 ? data.documents[0].region_1depth_name : 'unknown';
            const nowLocationGu = data.documents.length > 0 ? data.documents[0].region_2depth_name : 'unknown';
            setLocation(
                {
                    ...location,
                    latitude,
                    longitude,
                    nowLocationCity,
                    nowLocationGu,
                }
            );
        } catch (error) {
            setLocation({
                ...location,
                error: 'kakao API 호출 실패',
            });
        }
    };
    useEffect(() => {
        // dispatch(getLocation(loading))
        // setTimeout(() => {
        // }, 500);
        dispatch(getLocation(location))
    }, [location])

    return location;
};

export default useLocationHook;

 

useLocationHook은 현재 위치의 위도와 경도를 가져온 후 성공 시에 kakao api에 매개변수로 전달하여 return 하는 방식이다.

return 하기 전에 dispatch로 Redux로 전역관리하는 slice에 location 객체가 저장된다.

 

        getLocation(state, action) {
            const { nowLocationCity, nowLocationGu, latitude, longitude } = action.payload
            state.location.nowLocationCity = nowLocationCity
            state.location.nowLocationGu = nowLocationGu
            state.location.nowLatitude = latitude
            state.location.nowLongitude = longitude
        },

현재 위치

2) 현재 위치의 날씨

 

현재 위치의 날씨를 구하기 위해 hook을 하나만 만들려 했지만 코드가 상위부터 읽히는 것이 아닌 전체가 한 번에 읽히는 react 특성상 위경도를 XY좌표로 변환하는 hook과 XY좌표를 기준으로 날씨를 출력하는 hook을 나누었다.

 

 

* 실무, 고수들은 위치와 날씨를 가져올 때 hook을  사용하는지, hook을 나처럼 나누어 사용하는지 혹은 hook을 사용하지 않고 다른 방법(class 등)으로 하는지 아직 잘 모르겠다.

이번 프로젝트를 진행하면서 가장 어려웠던 부분이다. 비동기 / Axios, 전역변수 / Redux, hook이 처리되 후 실행되어야 하는 함수 및 다음 hook / useEffect 등등 배운 내용 + 구글링 하여 습득한 지식으로 진행하다 보니 코드도 무거워지고 비효율적으로 돌아가는 것 같다.

 

import { useState } from 'react';
import { useDispatch } from 'react-redux';
import { getConvert } from '../store/modules/acountSlice';
import { useEffect } from 'react';

const useConvertHook = (v1, v2) => {
    const dispatch = useDispatch()

    const RE = 6371.00877;
    const GRID = 5.0;
    const SLAT1 = 30.0;
    const SLAT2 = 60.0;
    const OLON = 126.0;
    const OLAT = 38.0;
    const XO = 43;
    const YO = 136;

    const [convertXY, setConvertXY] = useState({ x: 0, y: 0 })

    const toXY = (v1, v2) => {
        let DEGRAD = Math.PI / 180.0;
        let RADDEG = 180.0 / Math.PI;

        let re2 = RE / GRID;
        let slat3 = SLAT1 * DEGRAD;
        let slat4 = SLAT2 * DEGRAD;
        let olon2 = OLON * DEGRAD;
        let olat2 = OLAT * DEGRAD;

        const xy = {}

        let sn = Math.tan(Math.PI * 0.25 + slat4 * 0.5) / Math.tan(Math.PI * 0.25 + slat3 * 0.5);
        sn = Math.log(Math.cos(slat3) / Math.cos(slat4)) / Math.log(sn);
        let sf = Math.tan(Math.PI * 0.25 + slat3 * 0.5);
        sf = Math.pow(sf, sn) * Math.cos(slat3) / sn;
        let ro = Math.tan(Math.PI * 0.25 + olat2 * 0.5);
        ro = re2 * sf / Math.pow(ro, sn);
        xy['lat'] = v1;
        xy['lng'] = v2;
        let ra = Math.tan(Math.PI * 0.25 + v1 * DEGRAD * 0.5);
        ra = re2 * sf / Math.pow(ra, sn);
        let theta = v2 * DEGRAD - olon2;
        if (theta > Math.PI) theta -= 2.0 * Math.PI;
        if (theta < -Math.PI) theta += 2.0 * Math.PI;
        theta *= sn;
        xy['x'] = Math.floor(ra * Math.sin(theta) + XO + 0.5);
        xy['y'] = Math.floor(ro - ra * Math.cos(theta) + YO + 0.5);

        setConvertXY({ x: xy.x, y: xy.y })
    };
    useEffect(() => {
        toXY(v1, v2);
    }, [v1, v2]);
    useEffect(()=>{
        dispatch(getConvert(convertXY));
    },[convertXY])

    return convertXY;
}

export default useConvertHook;

 

위경도를 기상청 API에 사용 가능한 XY좌표로 변환해 주는 hook

 

import { useEffect, useState } from 'react';
import axios from 'axios';
import { useDispatch, useSelector } from 'react-redux';
import { getWeather } from '../store/modules/acountSlice';

const useWeatherHook = () => {
    const dispatch = useDispatch()
    const { nowX, nowY } = useSelector(state => state.acount.location)
    // console.log(nowX, nowY);
    const [weatherData, setWeatherData] = useState()
    const setWeather = async () => {
        const KMAAPikey = 'apikey'
        const now = new Date();
        let year = now.getFullYear();
        let month = now.getMonth() + 1;
        let day = now.getDate();
        let hours = now.getHours();
        let minutes = now.getMinutes();
        month = month < 10 ? '0' + month : month;
        day = day < 10 ? '0' + day : day;
        hours = hours -1;
        if (hours < 0) {
            now.setDate(now.getDate() - 1);
            year = now.getFullYear();
            month = now.getMonth() + 1;
            day = now.getDate();
            hours = 24 + hours;
        }
        hours = hours < 10 ? '0' + hours : hours;
        minutes = '00';

        const baseDate = `${year}${month}${day}`;
        const baseTime = `${hours}${minutes}`;
        const dataType = 'JSON';
        try {
            const response = await axios.get(
                `http://apis.data.go.kr/1360000/VilageFcstInfoService_2.0/getUltraSrtFcst?serviceKey=${KMAAPikey}&pageNo=1&numOfRows=1000&dataType=${dataType}&base_date=${baseDate}&base_time=${baseTime}&nx=${nowX}&ny=${nowY}`
            );
            const weatherItem = response.data.response.body.items.item
            const tem = weatherItem.find(item => item.category === 'T1H')
            const sky = weatherItem.find(item => item.category === 'SKY')
            const pty = weatherItem.find(item => item.category === 'PTY')
            setWeatherData({tem, sky, pty});
        } catch (error) {
            // console.error('--- ERROR ---', error);
        }
    };
    useEffect(() => {
        setWeather();
    }, [nowX, nowY]);
    useEffect(() => {
        if(weatherData){
            dispatch(getWeather(weatherData))
        }
    }, [weatherData]);

    return weatherData
}

export default useWeatherHook;

 

현재 시간을 기준으로 적절하게 조정하여 API를 호출하였다.

호출시 현재 온도와 날씨만 필요하므로 해당 url을 get 하고 filtering 하여 weatherData에 넣었다.

 

가이드
가이드

 

nowWeather, nowTem

 

그 결과 현재 날씨의 상태와 기온을 잘 가져올 수 있었다.

'🔥 부트캠프-웹 개발 🔥/오늘하날(개인프로젝트)' 카테고리의 다른 글
  • [DAY - 108] #12 개인프로젝트 '오늘 하날'
  • [DAY - 101] #10 개인프로젝트 '오늘 하날'
  • [DAY - 99] #9 개인프로젝트 '오늘 하날'
  • [DAY - 98] #8 개인프로젝트 '오늘 하날'
Yeonhub
Yeonhub
✨ https://github.com/yeonhub 📧 lsy3237@gmail.com
  • Yeonhub
    비 전공자의 Be developer
    Yeonhub
  • 전체
    오늘
    어제
    • 전체보기 (169)
      • 🔍 Tech 🔍 (19)
        • Front-End (11)
        • Back-End (4)
        • AI (1)
        • Server (1)
        • Etc (2)
      • 💡 원티드 프리온보딩 챌린지 💡 (14)
        • PRE-ONBOARDING_AI (11월) (1)
        • PRE-ONBOARDING_FE (2월) (2)
        • PRE-ONBOARDING_FE (1월) (2)
        • PRE-ONBOARDING_FE (12월) (9)
      • 🔥 부트캠프-웹 개발 🔥 (118)
        • HTML5 (7)
        • CSS3 (21)
        • JavaScript (27)
        • JavaScript_advanced (9)
        • React (24)
        • Next (1)
        • MYSql (5)
        • Node (5)
        • 오늘하날(개인프로젝트) (12)
        • 이젠제주투어(팀프로젝트) (7)
      • 💻 CS 💻 (1)
        • 알고리즘 (1)
      • ⚡ 코딩테스트 ⚡ (11)
        • JavaScript (11)
      • 📚 Books 📚 (6)
        • 클린 아키텍처 (2)
        • 인사이드 자바스크립트 (4)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • Github
  • 공지사항

  • 인기 글

  • 태그

    expo google map
    프론트엔드 테스트코드
    expo 길찾기
    bottom sheet
    javascript fcm
    node.js fcm
    expo 지도
    Node
    react native analytics
    expo fcm push
    node fcm
    라스콘4
    node cron
    라스콘
    expo admob
    expo fcm
    expo deep linking
    react native firebase analytics
    rn admob
    react vite
    rn bottom sheet
    react native expo fcm
    컴파운드 컴포넌트 패턴
    php node
    react native bottom sheet
    react native admob
    python node
    expo map
    node crontab
    expo node fcm
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
Yeonhub
[DAY - 102] #11 개인프로젝트 '오늘 하날'
상단으로

티스토리툴바