들어가기 전에

ISO 8601이란 ?

  • ISO 8601은 날짜와 시간을 나타내는 표준화된 형식을 정의한 국제 표준화 기구(ISO)의 표준입니다.
  • 이 표준은 날짜, 시간, 날짜 및 시간의 조합에 대한 표현 방법을 규정하고 있어 다양한 응용 분야에서 사용됩니다.

ISO 형식

  • 년-월-일 형식: 년도, 월, 일을 순서대로 표기합니다.
  • 시간 형식: 시, 분, 초를 순서대로 표기하며, 필요에 따라 소수 초를 추가로 표현할 수 있습니다.
  • UTC 표기: 날짜와 시간을 협정 세계시(UTC, 혹은 GMT)로 표기할 수 있습니다.
  • 시간대 정보: 시간대 정보를 포함하여 표기할 수 있습니다.
날짜: "2023-10-09"
날짜와 시간: "2023-10-09T14:30:00"
날짜와 시간, UTC: "2023-10-09T14:30:00Z"
날짜와 시간, 시간대 포함: "2023-10-09T14:30:00+03:00"

ISO 8601 표준을 보기 편하게 바꾸기

현재 상황

  • 모여타 개발 중 출발 시간을 표시해야 하는데 출발시간 데이터가 ISO 표준 형식으로 받아와지고있다.
  • 이를 잘 파싱하여 10월 06일 오후 7시 50분 과 같은 형태로 보여주고싶다.

년, 월, 일 파싱

  • 2023-10-09T14:30:00Z에서 년, 월, 일을 파싱하는 것은 쉽다.

  • Javascript의 slice 메소드를 이용하면 된다.

    
      const year = data.departureTime.slice(0, 4); // 2023
      const month = data.departureTime.slice(5, 7); // 10
      const date = data.departureTime.slice(8, 10); // 09

요일 구하기

영어로 된 요일 구하기

  • Javascript 메소드인 Date를 사용하여 영어로 된 요일을 구해줄 것이다.
    var newDate = new Date("2023-10-09T14:30:00"); // Mon Oct 09 2023 14:30:00 GMT+0900 (한국 표준시) 
  • 위 경우처럼 Date를 생성자로 호출할 경우 새로운 Date 객체를 반환한다.
  • 이 과정에서 우리는 영어로 된 요일을 얻을 수 있다.

한글로 바꿔주기

const days = ['일', '월', '화', '수', '목', '금', '토'];
var newDate = new Date("2023-10-09T14:30:00");
const day = days[newDate.getDay()];
  • getDay 메서드를 이용하면 요일에 따른 숫자를 반환한다.
    (Sun: 0, Mon : 1 등등)
  • 우리는 이를 한글로 바꿔주고 싶기 때문에 한글로 된 요일 배열 days를 만들고, getDay메소드로 받아온 숫자를 인덱스처럼 사용해주면 된다.

시간을 12시제로 바꾸기

  • 이제 남은 것은 14:30:00 등으로 표현된 시간을 오후 2시 30분으로 된 12시제로 바꿔주는 것이다.

숫자만 파싱해오기

     let timePart = date.match(/\d{2}:\d{2}/)[0];
  • 정규표현식을 이용해 "두자리 숫지 : 두자리 숫자"와 일치하는 패턴을 가져올 것이다.
  • 사용한 정규표현식을 간략히 설명하자면 \d는 숫자(digit)를 나타내고, {2}는 해당 패턴이 두 번 반복되어야 함을 나타낸다.
  • 즉 아래 첫 번째 소스 코드는 newDate에서 '숫자숫자:숫자숫자'와 매칭 되는 것을 찾으라는 뜻이다.
  • 그 중 0번째 요소를 반환하라고 했는데, 이는 우리가 원하는 숫자 외에 다른 데이터도 반환하기 때문이다.

  • timepart는 이제 숫자숫자:숫자숫자의 형태일 것이다. :를 기준으로 앞 뒤로 자르면 hour, minute으로 나눌 수 있다.
    const hour = timePart.split(':')[0];
    const minute = timePart.split(':')[1]; 

12시간제로 바꿔주기

  • 로직은 간단하다. 위에서 파싱한 hour이 12보다 크면 12를 빼주고, 아니면 그대로 가져가면 된다.
   if (hour < 12) {
      timePart = '오전 ' + hour + ':' + minute;
    } else {
      timePart = '오후 ' + (hour - 12) + ':' + minute;
    }

전체 코드

      const month = data.departureTime.slice(5, 7);
    const date = data.departureTime.slice(8, 10);

    const days = ['일', '월', '화', '수', '목', '금', '토'];

    const newDate = new Date(data.departureTime); // 요일을 영어로 얻기 위함
    const day = days[newDate.getDay()];

    let timePart = data.departureTime.match(/\d{2}:\d{2}/)[0];
    const hour = timePart.split(':')[0];
    const minute = timePart.split(':')[1];

    if (hour < 12) {
      timePart = '오전 ' + hour + ':' + minute;
    } else {
      timePart = '오후 ' + (hour - 12) + ':' + minute;
    }

취뽀 스테이션

  • 게시판을 만들고 있다
  • Toast ui Editor을 이용하여 만들고 있음
  • editor입력 → editorRef.current?.getInstance().getMarkdown() 을 이용하여 content 값을 가져온 후
  • 이를 useState의 setContent함수를 이용하여 넣어 content 내용을 firebase로 보내고 있었다.

문제 발생

  • set함수가 비동기로 동작해서 그런지 최초 onSubmit 함수 실행시 setContent가 제대로 실행되지 않는다.
  • 만일
    • ‘안녕하세요’ 입력 → 작성하기 버튼 누름 → onSubmit 함수 실행 → ‘안녕하세요 값을 가져옴’ → setContent(’안녕하세요’) → console.log(content) → 아무것도 안나옴
    • 그 다음 ‘반갑습니다’ 입력 → 위와 동일 → console.log(content) → ‘안녕하세요’ 출력

원인

  • set함수가 비동기로 동작하기 때문에 발행한 문제가 맞았다.
  • setContent를 통해서 content를 설정했다. (비동기)
  • content를 콘솔에 찍음 (동기)
  • 이렇기에 setContent가 content 설정을 완료하기 전에 console.log이 실행 된 것. 따라서 최초 실행시에는 빈 문자열이, 이후 실행시엔 이전 단계에서 설정한 content 값이 나왔던 것이다.

해결방법

  • useEffect를 사용하였다.
  • useEffect에 dependency를 content로 설정하여 content가 마운트 된 것을 감지하고 나서 함수를 실행하니 잘 해결 되었다.
  • 이번 일을 계기로 useState의 비동기 동작에 대해서 더 잘 이해하게 된 것 같다.

내가 뭘 하려고 했냐면요..

  • RN으로 카카오로그인을 구현하고 있었습니다.
  • koe006에러는 보통 redirectUrl, ClientId를 잘못 입력해서 발생하는 에러입니다.
  • 그런데 저는 카카오로그인 redirectUrl, ClientId 모두 제대로 받아 적용한 상태에서 발생한 에러라 원인 찾기가 정말 힘들었습니다.

해결방안

  • 4시간동안 이런저런거 다 시도해보고 결국 카카오디벨로퍼스에 문의한 결과 제 redirectUrl 뒤에 공백이 있다는 것을 알게되었습니다.
  • 알고보니 코드 내 줄바꿈이 공백으로 처리되어 공백이 들어갔던 것이었습니다.
  • 안드로이드 에뮬레이터에서는 문제없이 작동하고 ios 에뮬레이터 및 실물기기에서 에러가 발생해 ios 에러인가 싶었지만 공백 문제였습니다 …

문제코드

<WebView
    source={{
          uri: `https://kauth.kakao.com/oauth/authorize?response_type=code&client_id=${process.env.EXPO_PUBLIC_KAKAO_REST_API_KEY}&redirect_uri=
                    ${process.env.EXPO_PUBLIC_REDIRECT_URI}
}} />

해결 코드

<WebView
    source={{
          uri: `https://kauth.kakao.com/oauth/authorize?response_type=code&client_id=${process.env.EXPO_PUBLIC_KAKAO_REST_API_KEY}&redirect_uri=${process.env.EXPO_PUBLIC_REDIRECT_URI}
}} />

문의 남긴 카카오디벨로퍼스

https://devtalk.kakao.com/t/koe006-react-native-ios/132595

구현 배경

  • 졸업작품 취뽀스테이션에서 채용 공고를 보여주는 페이지를 구현해야했습니다.
  • 고민하다 사람인에서 채용 공고를 크롤링해 보여주기로 결정했습니다.

개발환경 세팅

cheerio 설치

> npm install cheerio

- cheerio는 Node 환경에서 파싱을 도와주는 라이브러리입니다.
- 단, 파싱을 도와주는 라이브러리이기 때문에 크롤링 할 페이지는 axios를 이용해 가져와야합니다.
- JQuery 문법을 사용해 css 선택자, class이름, id 등으로 요소를 찾아 데이터를 수집할 수 있습니다.

axios 설치

> npm install axios

- axios는 node.js와 브라우저를 위한 Promise 기반 HTTP 클라이언트입니다.
- 요청 및 응답 데이터 변환, 응답 인터셉트 등의 역할을 합니다.
- 우리는 axios를 이용해 크롤링 하려는 페이지의 html 값을 가져올 것입니다.

크롤링 할 페이지의 html 값 가져오기

  • 잡코리아의 채용공고 페이지를 크롤링 해옵니다.
import axios from "axios";

function Crwaling() {

const getHtml = async (keyword) => {
    try {
      return await axios.get(
        `https://www.jobkorea.co.kr/Search/?stext=${keyword}&tabType=recruit&Page_No=1`
      );
    } catch (error) {
      console.error(error);
    }
  };

}

크롤링한 html 값 파싱해 넣기

  • 이를 cheerio를 이용해 파싱합니다.
const parsing = async (page) => {
    const $ = cheerio.load(page);
    const jobs = [];
    const $jobList = $(".post");
    $jobList.each((idx, node) => {
      const jobTitle = $(node).find(".title:eq(0)").text().trim();
      const company = $(node).find(".name:eq(0)").text().trim();
      const experience = $(node).find(".exp:eq(0)").text().trim();
      const education = $(node).find(".exp:eq(0)").text().trim();
      const regularYN = $(node).find(".option>span:eq(2)").text().trim();
      const region = $(node).find(".long:eq(0)").text().trim();
      const dueDate = $(node).find(".date:eq(0)").text().trim();
      const etc = $(node).find(".etc:eq(0)").text().trim();

      jobs.push({
        jobTitle,
        company,
        experience,
        education,
        regularYN,
        region,
        dueDate,
        etc,
      });
      setJobs(jobs);
    });
  };

서비스 적용 모습

  • 서비스에 직접 적용하면서 치명적인 오류가 있었습니다...
  • 바로 CORS에러가 났다는 점.. 제가 맡은 사람인 페이지와 팀원이 맡은 잡코리아 페이지 모두 CORS를 허용해주지 않아 에러가 발생했습니다.
  • 결국 서버를 만들어 서버에서 크롤링 값을 가져온 후 CORS를 허용해 클라이언트로 보내주는 방식으로 해결했습니다.

추가적으로 공부한 점

  • 웹페이지와 DOM
    • 웹페이지는 HTML 형식으로 제공되는 문서입니다.
    • 웹 브라우저로 웹 페이지에 접근한다는 것은 서버로부터 해당 주소에서 제공하는 HTML 문서를 HTTP 통신으로 전달받는 것을 의미합니다.
    • 전달 받은 HTML 문서는 단순 텍스트 형태이기 때문에 프로그램에서 사용하기 좋은 데이터 구조로 표현해야하는데, 이 구조를 DOM이라고 부릅니다.
  • DOM 트리
    • 웹 페이지의 모든 요소를 Document 객체가 관리합니다.
    • 따라서 웹 페이지의 요소를 잘 관리하고 제어하기 위해서는 Document 객체가 웹 페이지 요소들을 잘 반영하는 자료구조를 가지고 있어야 합니다.
    • 그래서 Document 객체 모델인 DOM은 트리 자료구조의 형태를 가지고 있습니다.
  • HTML 코드로 DOM 알아보기
<!DOCTYPE html>
<html lang="ko">
<head>
    <title>옥돔 아니고 DOM</title>
    <meta charset="UTF-8">
</head>
<body>
    <h1>DOM이란?</h1>
    <p><strong>30분 걸려만든</strong>다이어그램입니다.</p>
</body>
</html>

+ Recent posts