본문 바로가기

개발/회고

[SS회고] React와 React Router

삘 받았을때 열심히 회고해야한다^_^

 

낄낄

 

사용한 웹 프레임워크

React

내가
1) 하이브리드 앱을 React Native로 만들려는 시도를 한 적이 있고,
2) 회사에서 자바스크립트도 다뤄보았고,
그래서 React를 웹 프레임워크로 선정했다.

React를 쓰면서 어려웠던 점은 버튼에 ripple 효과를 넣어볼까 하고 덤볐던게
지금으로서는 젤 기억에 남는다.

버튼의 동작은 router를 이용해서 다른 라우터를 push을 하는 것이었다.

그런데 버튼을 누르면 component의 state를 바꿔서 새로 렌더링을 하면서
버튼에 동그라미가 쓔욱 커지는 애니메이션을 주는데,
그러니까 push 동작이.. 안먹는 것이었다.

부들부들거리면서 어떻게 해야하나 고민했는데.

어차피 push 동작이 매우 빠르게 일어나기 때문에
ripple 효과가 보이도록 하려면 타이머도 넣어야하고..
복잡해질거 같아서 결국 gg하고 안넣었다..

React는 복잡한 UI 효과를 구현하기에 너무나 어렵구나..
라고 본업 Android 개발자는 생각했다..

또 state를 관리하는 프레임워크(MobX)를 도입할까 고민하기도 했었다.

이전에 React Native로는 로그인까지 필요한 앱을 만들려고 했어서 관리할 state가 정말 많았다.
하지만 서울사람은 hook으로 다 커버가 가능한 수준이라서 도입하지 않았다.

css는 간단하면 inline style로 넣었고 복잡하면 styled component를 사용했다.

css를 진짜 못해서 고민했는데...

 

아 킹받네


동기가 styled component를 추천해주었다.
css안에 props를 넘겨서 그 값에 따라 style을 쉽게 바꿀 수 있었다.
덕분에 개발속도가 빨라졌다.

하지만 복잡한 조건문이 들어가게 되면 좀 괴랄해지는거 같다..

Border만 있는 Button을 만들면서 두 개의 prop 값에 따라 값을 분기치고 싶었는데,
결국은 이렇게 코드가 나왔다. 가독성을 우선으로 했다..

const ButtonWithBorder = styled.button`
  ${({selected, enabled}) =>
    selected &&
    enabled &&
    css`
      background-color: ${colors.button.bg.enabledSecondary};
      border: 0.5px solid ${colors.button.bg.enabledSecondary};
      color: ${colors.button.bg.text};
      cursor: pointer;
      &:hover {
        box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.1);
      }
    `}
  ${({selected, enabled}) =>
    selected &&
    !enabled &&
    css`
      background-color: ${colors.button.bg.disabledSecondary};
      border: 0.5px solid ${colors.button.bg.disabledSecondary};
      color: ${colors.button.bg.text};
    `}
    ${({selected, enabled}) =>
    !selected &&
    enabled &&
    css`
      background-color: ${colors.button.border.bg};
      border: 0.5px solid ${colors.button.border.enabled};
      color: ${colors.button.border.text};
      cursor: pointer;
      &:hover {
        box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.1);
      }
    `}
    ${({selected, enabled}) =>
    !selected &&
    !enabled &&
    css`
      background-color: ${colors.button.border.bg};
      border: 0.5px solid ${colors.button.border.disabled};
      color: ${colors.button.border.disabledText};
    `}
  border-radius: 50px;
  padding: 0.5em 1.5em;
  vertical-align: middle;
  font-size: calc(10px + 1.5vmin);
  font-family: 'Song Myung';
`;


그리고 반응형 웹을 지향하려 노력했따..

React 프로젝트를 init하면 뷰포트 설정은 이미 되어있다.
App의 height도 이미 100vh로 설정이 되어있던 걸로 기억한다.
(React 굳굳~)

그외에 자잘하게 px로 고정하지 않고 vh, vmin, em 단위를 이용하여 크기를 조정했다.
디자이너는 없기 때문에 계속 바꾸면서 이뻐보이는 값으로 설정했다^^

또 Consistency를 위해 Route가 모두 공통으로 사용하는Common component를 만들어서
모든 페이지가 동일한 템플릿과 간격을 유지하도록 작업했다.

마지막으로 가장 최근에 해결했던 이슈는
index.html의 최상위 div height를 100vh로 고정했더니
모바일 브라우저에서는 urlBar 크기 만큼 컨텐츠가 밀려서 스크롤이 되는 문제가 있었다.

찾아보니 모바일 브라우저는 urlBar가 스크롤이 되면 사라지기 때문에
그 크기를 screen size에서 제외하지 않는다고 한다.

아주 좋으신 분이 해결책을 공유를 해두셨더라!
최소 천재이신분.. 찡긋 >_-


https://css-tricks.com/the-trick-to-viewport-units-on-mobile/

 

The trick to viewport units on mobile

Viewport units have always been controversial and some of that is because of how mobile browsers have made things more complicated by having their own

css-tricks.com

 

<2021.09.13 수정>

 

저렇게 resize 될때마다 window의 inner height을 구하도록 했더니,

페이지 로드부터 사이즈가 딱맞게 나오지 않고 스크롤 후에 사이즈가 변하는 현상이 발생했다.

 

그래서 height를 100%로 먹이면

자동적으로 urlBar이던 safari의 네비게이션바이던 모두 고려한 크기를 잡는다는 사실을 알게 되어서.

이 방법을 적용했다.

 

React로 구현할때는 index.css안에 전역적인 style을 유의해야 한다.

나의 경우에는 index.css안에 상위 태그인 html, body에 대한 style이 있었고 

거기에도 height: 100%; 을 추가해줘야 한다.


index.html에는 이렇게 코드가 들어갔다.

  <body>
    <div style="height: 100%; width: 100%;">
      <div id="root"
        style="height: -moz-calc(100% - 50px);
        height: -webkit-calc(100% - 50px);
        height: calc(100% - 50px);
        overflow-x: hidden;"></div>
      <div id="ads" style="position: fixed; bottom: 0; height: 50px; width: 100%;">
      ...
      </div>
    </div>
  </body>

 

React Router

웹의 대세는 SPA라 했던가!

 

스파-


사실 나는 대세는 잘 몰랐는데.. 본래가 클라이언트 개발자다.
웹 서버를 구축하려고 보니 가슴이 답답하고 먹먹해지고 웅장해지기까지 해서^^

클라이언트 단에서 라우팅까지 해주는 것이 개발하기 쉬울 것이라 생각했다.

React Router가 가능하게 해주는 것은 다음과 같다.

클라이언트 코드에 Route를 쪼개준다.
Route라 함은 Express에서 그 Route와 동일하다.
param에 따라 분기로 페이지를 보여주는거다.

그래서 유저가 브라우저에서 I'm 서울사람 페이지에 들어오면,
브라우저가 우리 서버로부터 한방에 싱글 페이지를 받아온다.

유저가 요것저것 인터랙트를 하면~~
웹페이지는 서버에 다음 페이지를 달라고 할 필요없이 내부적으로 다음 페이지로 라우팅을 한다.

물논..

브라우저에 url을 full path로 쳐서 들어오게 되면
웹 페이지에서 라우팅할 도리가 없당.. 웹둥절..

나도 처음엔 이것 때문에 어리둥절했다..?

솔루션은 가능한 path들을 모두 서버에 넣어주고
서버에서 해당 path가 들어오면 index.html을 뱉어내도록 구현해야 한다.

코드는 요렇게 준비하면 된다.

const apis = [...];
apis.forEach((api) => {
  router.get(api, (req, res, next) => {
    res.sendFile(path.resolve(__dirname, '../../client/build', 'index.html'));
  });
});


가장 짜치는 일은
존재하는 Route를 full path로 쳐서 들어오는 일이다.

왜인지 설명하려면 구구절절하다..
그리고 나만 짜치는 걸수도;;

Router를 이용하면 3가지의 props를 사용할 수 있는데,
1) history: push, replace로 라우팅할 때 사용
2) location: 현재 경로 + url query
3) match: 어떤 Route에 매칭되었는지 + param

근!데!

라우팅을 할 때 state라는 prop를 설정할 수 있는데,
그러면 다음 페이지에서 location.state를 이용하여 이전 페이지의 데이터를 얻을 수 있다.
고마운 눔이다 ㅠㅠ

나는 이걸 이용해서 데이터를 보내는 방식으로 구현을 했는데..
(지금와서 생각해보니,, mobx 썼어야 했던건가.. 갑자기 현타가 온다;)

full path로 들어온 경우에는 당연히 state가 존재할 수가 없다.
꼭 필요한 선수 정보라고 해도 말이다...

그래서 이 경우에는 root url로 다시 라우팅하였다;

그리고 React의 dynamic import를 활용하여 code splitting을 했다.

SPA의 단점은 앱 규모가 커지면 자바스크립트 크기도 커진다는 것이다.
그렇게 되면 한 방에 받기가 매우 부담스러울 것이다..

물논.. 서울사람은 엄청 큰 앱은 아니지만!
좋은 기술은 꼭 써줘야 직성이 풀린다^^

그래서 자바스크립트 코드를 chunk로 쪼개 쪼개고
필요할때 마다 코드 chunk로 import하면서 사용하게 된다!

나는 해당 블로그 글을 참고해서 Route 단위별로 쪼개도록 구현했다.


https://medium.com/humanscape-tech/react%EC%97%90%EC%84%9C-%ED%95%B4%EB%B3%B4%EB%8A%94-%EC%BD%94%EB%93%9C-%EC%8A%A4%ED%94%8C%EB%A6%AC%ED%8C%85-code-splitting-56c9c7a1baa4

 

React에서 해보는 코드 스플리팅 (Code Splitting)

안녕하세요, 휴먼스케이프 개발팀 oliver입니다.

medium.com