[토이 프로젝트] 솔로몬Day 1

도깨비젤리

·

2021. 6. 16. 01:33

들어가는 말


지난 주말, 친구 A에게 연락이 왔다. 같이 프로젝트 하나 하자고 한다.

 

나는 포트폴리오도 채워야했고, React도 좀 더 연습해보고 싶어서 안 그래도 뭔가 해볼까 하고 있던 참인데, 이게 왠 떡이냐?? 거기다가 이 친구, 경력도 빵빵하다. 오히려 내가 부탁하고 싶은 입장이였는데, 잘되었다.

 

냉큼 ㅇㅋㅡ 를 때리고 바로 아이디어 회의에 돌입했다.

 

 

버스 탈 생각에 싱글벙글

 

 

처음에는 우리 개발팸 ( a.k.a 대학교때부터 질기게 이어온 못난 놈들 ) 들이 운영하는 기술 블로그를 만드려고 했는데, 구현하고 싶은 기능을 이것저것 붙이다보니 규모가 너무 커져서 노선을 바꾸기로 하였다.

 

물론 나도 좀 빡세더라도 으리으리한걸 만들고 싶었지만, 생각해보면 너와 나. 개발자로서는 처음 아니던가?? 한 입에 삼키려다가 입 찢어지는 모습이 어째서인지 눈에 선명하다. 

 

그래서 첫 프로젝트는 겸손하게 가기로 했다. 이번 프로젝트의 메인 목표는 "너와 나의 개발 케미 맞추기"로 정하고, 다시 한번 아이디어 회의에 돌입했다.

 

그 결과, "보드게임 추천 앱"을 만들기로 하였다. 둘 다 보드게임을 좋아하고, 실생활에 사용할 수 있는 여지가 충분하며,결정적으로 우리가 활용할 수 있는 잘 만들어진 API도 찾았기 때문이다. 좋아, 그럼 바로 시작해볼까??

 

 

 

 

잠깐! 개발 멈춰!!!!

 

결과 페이지를 어떻게 구성할지 서로 의견이 갈렸다. 나는 결과 페이지에 게임 설명을 간단히 텍스트로 표시하고 싶었다. 근데, 우리가 쓸 API는 게임 설명을 영어로 제공했다. 국내 유저를 대상으로 하는 프로젝트이기 때문에, 나는 A에게 해당 API 응답을 기반으로 따로 DB를 떠서 서버를 띄우자고 했다. 근데 이걸 A가 굉장히 반대했다. DB를 따로 구축하는 건 비효율적이라는 이유여서였다.

 

이에 "나는 필요하다면 하는게 맞지 않냐, 그리고 우리 댓글 작성 기능 넣기로 하지 않았냐. 그럼 어짜피 서버 띄워야하니까 하는 김에 같이 하자!" 라고 말했는데,  A는 잠시 생각하더니 이렇게 말한다.

 

 

그럼 서버리스로 만들자. 내가 DynamoDB  올릴께.

 

 

너 그런것도 할 줄 알았니??

 

이래서 머슴살이를 해도 대감댁에서 해야한다. 이렇게 방향이 잡히니, 이후 진행은 정말 화살 같이 빠르게 지나갔다.

빠르게 피그마로 목업을 하고, 바로 개발에 돌입했다. 나랑 A는 활동시간이 서로 달라, 트렐로로 업무 상황을 공유하기로 했다.

 

피그마로 구성한 프로토타입

이렇게 우리의 첫 프로젝트가 시작되었다.

 

 

TIL


사실 연재물 쓰기로 한 이유가 프로젝트하면서 배운거 정리하려는 목적이였는데, 어째 서론이 드럽게 길어졌다.

여기서부터는 빠르게 가자

 

 

 

1. Marterial-ui : makeStyles


Marterial-ui는 대표적인 React UI 프레임워크이다. 이 프레임워크에서 제공하는 makeStyles Hook를 이용하면 컴포넌트의 스타일을 손쉽게 지정할 수 있다.

 

import React from 'react'
import { makeStyles } from "@material-ui/core/styles";


const useStyles = makeStyles({
  detailArea:{
    border: "2px solid blue"
  },
  image : {
    width: "100%",
  },
  video:{
    margin : "0 auto",
  },
  videoAlign:{
    textAlign: "center",
  }
})


const GameDetails = ()=>{
  const classes = useStyles()
  return(
    <div className={classes.detailArea}>
      <img className={classes.image} src="https://cdn.shopify.com/s/files/1/0513/4077/1515/products/catan-board-game.jpg?v=1609629082" alt="보드게임"></img>
      
      <h3 className={classes.videoAlign}>
        룰 설명
        <iframe className = {classes.video} src="https://www.youtube.com/embed/SvmX053bQZ0" title="gamerule"></iframe>
      </h3>
    </div>
  )
}

 

이렇게 makeStyle를 작성한 다음, 이를 호출하면 makeStyles안의 내용이 css 요소와 같아진다고 생각하면 된다.

즉, css로 html 태그에 class를 먹이는 것과 유사하게 JSX를 다룰 수 있는 것이다.

 

A군 曰 : "React는 컴포넌트 단위로 재활용을 한다. 요소에 스타일을 먹일 때, 너처럼 css 파일을 따로 빼서 거기서 스타일을 빼올 수도 있지만, 별로 React 스러운 방법은 아니다. React를 만질 때는 항상 컴포넌트 단위로 생각하는게 협업에 크게 도움이 될꺼다."

 

 

 

2. Marterial_UI : endAdornment


일부 컴포넌트에는 props로 endAdornment 혹은 startAdornment라는 것을 줄 수 있다. Adornment의 사전적 의미는 "장신구"라는 뜻이다. 이를 사용한다면, 마치 장신구를 다는 것처럼, 컴포넌트 시작 위치 혹은 종료 위치에 다른 컴포넌트를 달아줄 수 있다. 나는 Input 컴포넌트에 이어서 Button 컴포넌트를 달기 위해서 이 props를 사용했다.

 

	<FormControl>
        <Input 
          placeholder='댓글 입력' 
          fullWidth={true}
          endAdornment={<Button variant="contained" color="primary">제출</Button>}
          ></Input>
      </FormControl>

 

 

3. 환경 변수에 접근하는 방법


 

API 키를 같이 민감한 정보는 직접 코드에 박아넣지 말고, .env 파일을 만들어서 거기서 참조해오는 것으로, 외부로 노출 되는 것을 막아야한다.

 

각 프레임워크마다 참조하는 방식이 조금씩 다른데, React에서는 .env.development 파일을 만들고, REACT_APP_XXXXX = "OOOOO" 라 작성한 뒤, process.env.REACT_APP_XXXXX로 비밀스러운 값에 접근한다.

 

 

 

4. 함수 컴포넌트는 첫글자는 무조건 대문자로 시작해야한다.


 

JSX는 소문자 태그 이름은 HTML 태그로 간주하기 때문이다.

 

 

 

5. React-Router : Route 설정 / 파라미터 읽기


 

1. Route를 설정 할때는 '/' path를 가지는 컴포넌트가 최하단부에 위치하도록 해야한다. 이는 React Router의 디폴트 매칭 규칙 때문인데, React Router는 path prop의 경로와 현재 URL을 비교하면서 전체가 아니라 앞부분만 일치해도 매치되는것으로 간주하기 때문이다. 따라서, '/'로 시작되는 path는 '/'뿐만 아니라 /로 시작되는 모든 path와 매치 된다!!!!

이것 때문에 얼마나 골치 아팠는지 모른다.

 

    <Router>
        <Switch>
          <Route path="/detail/:boardgameId" component={Detail} />
          <Route path="/" component={Akinator} />
        </Switch>
    </Router>

 

 

2. Route로 설정한 컴포넌트는 3가지 props를 전달 받는다.

  1. history : push,replace를 메서드를 이용해 다른 경로로 이동할 때 사용
  2. location : 현재 경로에 대한 정보와 URL 쿼리에 대한 정보를 가지고 있음
  3. match : 어떤 라우트에 매칭 되었는지에 대한 정보와 URL에 적힌 params를 가지고 있다.

 

/ 이하에 담긴 정보를 빼려면, match 객체를 사용해야한다. 위 코드 블럭 처럼 /:변수명꼴로 URL에 적힌 값을 컴포넌트에서 params로 쓰겠다고 지정해주자. 위 내용을 해석하자면, Detail이라는 컴포넌트는  /detail/{Random_String} 이라는URL을 가질때 연결되는데, 이때 {Random_String}에 해당하는 값을 boardgameId라는 이름으로 쓰겠다는 뜻이다.

 

그럼 이제 Detail 컴포넌트에서 사용해보자

 

const Detail = ({match}) => {
  const boardgameId = match.params.boardgameId
  console.log(boardgameId)

props로 match를 구조분해할당 해주고, match의 params에 접근한 다음, App.js에서 선언한 변수명인 boardgameId를 찍으면 {Random_String}이 나온다.

 

 

 

🔥Day 1을 마치며🔥


이번 프로젝트를 통해 본격적으로 React를 배우고 있다. 언제나 그렇듯, 배움은 어렵지만 그 열매는 달콤하다. 이번 프로젝트를 통해 React를 좀 더 내 것으로 만들 수 있기를 바란다.