[TIL] 220124

먼지·2022년 1월 23일
0

TIL

목록 보기
16/57
post-thumbnail

2022-01-24 월요일
많이는 못 해도 찍먹이라도 하기..! & 뽀모도로 타이머

일일회고

  1. 오늘의 도전과 배움
    input pattern 정규식, token 만료일 로컬스토리지로 관리, 스토리북 찍먹, ref대신 id 사용해서 dom 조작, 등등

  2. 궁금하거나 어려웠던 점
    git commit message 작성법과 커밋 단위... convention, npm npx yarn 차이!

  3. 내일 해보고 싶은 것들
    react-payments CreateCard의 input들 컴포넌트 분리하고 story book 적용해 보기!
    오늘보다 더 열심히 공부하고 그만 자책해야지ㅜ 막상 집중하면 우울함이 사라지기도 하는데 우울한 감정이 느껴지면 무엇을 시작할지 정해봐야겠다


  1. TIL 의미있게 작성하는 법 찾기 + notion
    전부 다 적으려고 하지 않고 설명들은 것을 기록하기 까먹을 것 같은 거를 기록
    잘 정리하려고 하지 않기. 하지 못하더라도 이게 맞을까? 라도 정리하기
    책이나 문서에 나오지 않는 것! 토끼님의 귤팁 ex) pattern을 이용한 validation 검증

참고
[Github] TIL 작성법
개발자의 Notion 활용하기
Velog 간단 사용법

react-payments

  • storybook도 조금 읽어보기..
  • 일단 만들고 pr branch 등 Git 연습 (드림코딩, 책, 유튭)

story book - Visual TDD

레오님이 알려주신 사이트!
Storybook 200% 활용하기
storybook tutorials - visual tdd

핵심 아이디는 코드를 작성?하기 전에 테스트를 먼저 짠다. 미리 멀 만들지를 기대하는 결과를 정의 (jest, cypress)
그러나 망한다. UIs 를 만들 때는 tdd를 만들기가 어려움. 컴포넌트에 텍스트가 있다던지 어떤 모양이 있는지 cypress, jest는 테스트 가능하지만 (다크모드)
브라우저 중에 하나라도 다른 스타일이 나오는 경우! (사파리, 파이어폭스, 크롬, 웨일, ..) 혹시라도 있을지 모르는 것을 검사
백 개 중에 하나만 불량이어도 문제 사파리 구버전, 크롬 구버전 등을 한땀한땀 테스트 -> 그거를 visual tdd로 만들 수 있음

jest, vitest - unit test. integration 통합 테스트
cypress - 실제 브라우저에서 돌아가는 e2e test
visual test - story book 눈에 보이는 것들

정규표현식

참고
html input pattern 정규표현식 모음

React ref, HTML label tag, 함수형 프로그래밍 ?!

useRef hook만 알고 있었는데, 전에 토끼님이 forwardRef도 있는데 별로 선호하지 않는 방식이라고 하셨다 ㅎ 토끼님 말을 맹신하는 나는 일단 이런 게 있구나 읽어봐야지

참고
[React] forwardRef 사용법
함수형 프로그래밍 — Curry 와 Partial Application
HTML label 태그 for 사용법 및 for 없이 사용법

useRef -> Document.getElementById

이전 input을 조건에 맞게 입력 시 자동으로 다음 input element로 focusing 되도록 만드는 부분에서 모든 input dom을 ref를 가져와 연결해서 handleInputChange로 전달했는데 가져와야할 input이 많아서 코드가 복잡했다.

import React, { useRef } from 'react';

const CreateCard = () => {
  // 모든 input element를 ref로..
  const expirationMonthElem = useRef(null);
  const expirationYearElem = useRef(null);
  const usernameInputElem = userRef(null);
  const securityCodeElem = useRef(null);
  ...
  
  function handleInputChange(validate, nextElem) {
    return e => {
      const { name, value, pattern } = e.target;
      ...

      if (validate(value)) {
        nextElem.focus();
      }
    };
  }
  
  return (
    <div className="input-container">
      <label htmlFor="expiration-month" className="input-title">
        만료일
      </label>
      <div className="input-box w-50">
      <input
        ref={expirationMonth}
        id="expiration-month"
        className="input-basic"
        type="text"
        placeholder="MM"
        name="expirationMonth"
        value={expirationMonth}
        {/* handleInputChange(validate, nextElem) */}
        onChange={handleInputChange(v => v.length > 1, expirationYearElem)}
        minLength={2}
        maxLength={2}
        pattern="^(0[1-9]|1[0-2]|[0-1])$"
      />
      <input
        id='expiration-year'
        ref={expirationYear}
        onChange={handleInputChange(v => v.length > 1, usernameInputElem)}
        ...    
      />
    </div>
  </div>
  );
}

ref를 쓰지 않고 element의 id를 전달받아서 getElementById로 가져와 focus()를 달았는데 리액트에서 이렇게 사용해도 되는지 성능상으로는 모르겠지만 코드가 깔끔해졌다.

const CreateCard = () => {
  function handleInputChange(validate, nextElemId) {
    return e => {
      const { name, value, pattern } = e.target;
      ..
      const nextElem = document.getElementById(nextElemId);

      if (validate(value)) {
        nextElem.focus();
      }
    };
  }
  
  return (
    <div className="input-container">
      <label htmlFor="expiration-month" className="input-title">
        만료일
      </label>
      <div className="input-box w-50">
      <input
        id="expiration-month"
        {/* handleInputChange(validate, nextElemId) */}
        onChange={handleInputChange(v => v.length > 1, 'expiration-year')}
		...
      />
      <input
        id='expiration-year'
        onChange={handleInputChange(v => v.length > 1, 'username')}
        ...    
      />
    </div>
  </div>
  );
}

팀프로젝트

token 관리

로그인 후에 정상적으로 token이 오면 자바스크립트 Date 객체를 이용해서 토큰 만료일인 24시간 후의 정보를 setDate 후에 localStorage에 같이 저장하고, context에서 현재 날짜와 로컬 스토리지의 만료일을 비교하여 user key를 관리!

// constext.js
import React, { createContext, useContext, useState, useEffect } from 'react';
import { memberApi } from './api';

const UserContext = createContext(null);

export function UserProvider({ children }) {
  const [state, setState] = useState({
    loading: true,
    t: null,
    user: null,
    error: null,
  });

  // 1. 로컬스토리지에서 'user' key에 유저 정보를 가져온다
  // {"token":"...","memberId":1,","expireDate":"2022-01-25T03:05:19.537Z"}
  const userLS = JSON.parse(localStorage.getItem('user'));

  const getUser = async () => {
    // 2. user가 없으면(로그인 x) return
    if (!userLS) return;

    // 3. 만료일 정보를 local storage에서 빼오고
    const expireDate = new Date(userLS.expireDate);
    // 4. 현재 date 정보를 now에 저장
    const now = new Date();
    // 5. 현재 date와 만료일을 비교해서 지났으면 user 정보 로컬스토리지에서 삭제 
    if (expireDate < now) {
      localStorage.removeItem('user');
      return;
    }

    try {
      const { data } = await memberApi.getUser(userLS.memberId);

// Login.jsx
import React, { useState } from 'react';
import { memberApi } from '../api';
import { useUser, useSetUser } from '../context';

const Login = () => {
  ...
  const onSubmit = (e) => {
    e.preventDefault();
    memberApi
      .login({ loginId, password })
      .then((res) => {
        const tomorrow = new Date();
        tomorrow.setDate(tomorrow.getDate() + 1);

        localStorage.setItem(
          'user',
          JSON.stringify({ ...res.data, expireDate: tomorrow.toISOString() })
        );
        const userLS = res.data;
        memberApi.getUser(userLS.memberId).then(({ data }) => {
          setUser((prev) => ({
            ...prev,
            loading: false,
            t: userLS.token,
            user: { id: userLS.memberId, data },
            error: null,
          }));
        });
      })
      .catch((err) => {

    ...
    
    return ...
};

근데 저기서 if 부분이 잘 동작했는데 브라우저 콘솔 창에서 연습하니까 비교가 안 되는 거임!! <- 오타였음 호호
탐토님과 미량님께서 getTime으로 비교하는 게 맞는다고 하셔서 수정했다. 수정전도 작동은 하지만 getTime()을 쓰는 것이 좀 더 명시적인 느낌인 듯 ㅎ

// 수정전
    const expireDate = new Date(userLS.expireDate);
    const now = new Date();
    if (expireDate < now) { 
    ...
    
// 수정후
    const expireDate = new Date(userLS.expireDate);
    const now = new Date();
    // 5. 현재 date와 만료일을 비교해서 지났으면 user 정보 로컬스토리지에서 삭제 
    if (expireDate.getTime() < now.getTime()) {
    ...

Javascript Date

참고
MDN - JavaScript Date
W3Schools - JavaScript Get Date Methods
javascript 날짜 포멧 간단 표현? toISOString()

자바스크립트 내장 객체 Date의 정적 메서드와, getDate() getTime() getYear() toISOString() 등의 여러 인스턴스 메서드 알아감~!


드림코딩 리액트 강의

3.1 필요한 툴 설치

  • 터미널 - 맥 iterm2 윈도우 cmder
  • Git - 소스코드 버전관리 & 깃헙 저장소에 올리기
    https://git-scm.com/downloads
  • Node & npm - node 설치 시에 npm도 같이 설치됨
  • npm 보다 빠른 yarn!
    페이스북에서 만들어진 패키지 매니저로 npm 위에서 동작하므로 package.json 파일 그대로 유지하면서 호환이 가능하게 사용할 수 있음
    npm install yarn --global

3.2 중요한 툴들 설명

  • Node.js - 자바스크립트를 실행할 수 있는 환경
    "JavaScript everywhere"
    어느 곳에서나 자바스크립트로 프로그래밍이 가능한 프레임워크
    백엔드 서버 만들기, 서버사이드 렌더링, 스크립트 만들기 등을 만들때도 이용함

  • npm - Pakage Manager
    라이브러리. 패키지들을 쉽게 관리할 수 있게 도와줌
    명령어 하나로 라이브러리 설치와 버전 업데이트가 가능

  • npx - 설치하는 것이 아니라 원하는 라이브러리를 실행할 수 있게 도와줌
    npm은 설치하고 업데이트만 하는 것만 할 수 있고 그 라이브러리를 실행하지는 못함..?

  • npm과 npx의 차이
    - 미량님
    npm은 라이브러리를 설치할 때 즉, 버전관리가 필요할 때 사용합니다. npm install 하면 package.json에 버전과 함께 디펜던시 목록에 추가가 되는 거처럼요. npx도 설치입니다. 근데 얘는 버전을 곁들이지 않은 일회성으로 모듈을 설치하고 끝!인 거예요
    - [Node] npm vs npx vs yarn
    예로, 다른 사람의 깃허브 레포지토리에서 다운받아 실행만 시켜보고 싶다고 가정해 보자. package.json의 scripts 중 하나를 실행하고 싶을 때 npx와 스크립트를 적으면 패키지 설치를 하지 않고 실행을 할 수 있다.
    개발을 하는 입장이라면 npm과 npx의 차이를 못 느낄 수 있지만, 실행하는 입장에서는 크게 다가오는 차이점이다.

3.3 리액트 툴

create-react-app은 유용한 툴들을 한번에 자동 설치해줌
Create React App
현업에서는 cra동 자동 설치하는 것보다 실제로 필요한 것들을 직접 Configuration해서 사용함.

yarn create react-app directory?

start - 작성한 코드를 실행
build - 우리가 만든 앱(제품)을 배포
test - 우리가 작성한 유닛 테스트를 실행
eject - 굉장히 많은 툴들이 cra를 이용하면 많은 툴들이 박스 안에 잘 포장이 되어져 있음. 박스 안에 아이들(웹팩, 바벨 등)을 다 확인하거나 손수 수정하거나 설정할 때 이용

실행! yarn start
중지 컨트롤 + D

3.4 프로젝트 구조 설명

  • .gitignore - 깃에 트레킹하고싶지않다 추가
  • package.json - 외부적인 라이브러리 버전들이 명시됨
  • yarn start는 실질적으로 리액트 스크립트의 스타트를 실행하는 것과 동일함
  • README.md - 프로젝트에 대해서 설명. 맨날 뭔가 아까워서 안 지웠는데 지워도 됨!
    잘 정리하기..! commit message도..
  • public - 사용자에게 배포할 때 외부적으로 보여지는 대표적인 아이들(index.html, favicon, img...)
  • manifest.json - 나중에 PWA 프로그래시브 웹 어플리케이션을 만들 때 필요함
  • robots.txt - 웹 크롤링에 이용함

  • 앞으로의 계획 짜기!
  • 개인 프로젝트
  • 책 읽기 (클린코드!, 뇌과학)
  • 운동 😇
profile
꾸준히 자유롭게 즐겁게

0개의 댓글