[우아한테크코스 #11] 인라인 스타일과 함께하는 11주차 회고

NinjaJuunzzi·2022년 5월 8일
6

우아한테크코스

목록 보기
14/21
post-thumbnail

감정회고

이번주는 코로롱이 끝난 주..! 정확히 수요일날부터 나갈 수 있었지만.. POCO의 권유로 재택으로 코스를 진행했다..
(ㅇㅈㅇㅈ 일어나서 준비다했지만 다시 잘 수 있어서 행복했습니다..)

좀 자고 일어나니 스크럼 시간이었기에.. 진행 ! 스크럼 시간에는 항상 외롭다. 모두들 만나서 하하호호 할 때 나는 음흉하게?칙칙하게? 모니터 앞에서.. 그들을 바라보다보니 뭔가 외로운 기분이 들었던 것 같다. 얼른 크루들 보고싶다고 생각하게 되었음 ㅠ

(킥킥 증거임)

후 다시 낮잠 자버렸다. ㅋㅋㅋ 확실히 재택은 날 게으르게 만든다. 내가 게으른게 아니다. 재택이 날 게으르게 하는거다 !! 👻👻👻 아무튼 마즘 ㅋㅋ

전체적으로 재택하는 한 주 동안 공부를 정말 안한 것 같다 ㅠㅠ 뭔가 코로롱 증상때문인지 뭔지 되게 무기력해졌다.. 빨리빨리 추가 기능들을 개발했어야 했는데 하루에 세 시간도 안한듯 흑 .. 그렇게 그렇게 우여곡절 끝에 스텝2까지 제출 !

리액트에 들어서고 부턴 기능이 완성되고 리팩토링이 끝나도 풀리퀘를 보내지 못하겠다. 자꾸 더 이쁜 코드를 만들 수 있을 것 같은 기분? 그리고 가끔 가끔 나에게 오는 궁금증들을 해결하려다보니 자꾸 풀리퀘 일자가 느려지는 느낌이다.

- 너무 길어질 때는 적당히라는 말을 되새기자

- 궁금증을 탐구하는 시간을 하루에 몰빵하지말고 여러 날로 분배시켜 차근차근 해봐야겠다.

기술회고

inline-style은 왜 문제가 될까요? (feat. 객체로 전달되는 prop)

기존에도 알고있던 지식이었는데 그전의 준찌는 이를 별로 궁금해하지 않았다. 근데 최근에 해결할 수 있는 몇가지 방법이 있지 않을까 생각이들어 탐구해보고자 함!

  • 과거의 준찌 : 에잉? inline-style 활용하는 곳 몇 군데 없으니깐 걍 냅둬버리자 ~ 치명적이지도 않은 것 같은데 크크 고민안해~ 술이나 먹으러 가야징~

  • 현재의 준찌 : 해결해보고싶어.. 해결해보고싶어.. 피할 수 없다면 즐겨야지...

힌트

{} === {} // false

요약

  1. css로 스타일링을 하다보니 불가피하게 인라인 스타일로 UI를 표현해야했음.

  2. 객체가 새롭게 생성되니 객체 내부의 속성들이 변경되지 않았음에도 재조정함.

// style prop에 들어가는 객체는 매번 새로운 객체가 된다.

<div className="small-card" style={{ backgroundColor: CARD_TYPE[cardType]?.color ?? '#e5e5e5' }} />
  1. 이 문제를 해결하고자 여러 방법(2가지)으로 시도해봤으나 다들 트레이드오프가 존재하였음.

1트
함수형 컴포넌트 스코프 내부에 지역변수로 선언해두고 이를 전달해주면 되지 않을까?

  const style = useMemo(
    () => ({ backgroundColor: CARD_TYPE[cardType]?.color ?? '#e5e5e5' }),
    [cardType],
  );
 
<div className="small-card" style={style} />

위처럼 작성하게 되면 .small-card 리액트 엘리먼트가 재조정될 때는 style 식별자의 참조 값이 재설정되는 경우일 것이다.

useMemo로 메모이제이션 해두었으니 사실상 cardType이 변경될 때만 style 객체가 새로운 참조값을 갖는 새 객체가 될 것이고 재조정이 발생하겠지!

하지만 트레이드오프가 있다.

  • 만약 inline-style 을 적용하는 엘리먼트가 수백개라면? 수백개의 지역변수가 존재하게 되겠지?

위 같은 문제로 지역변수를 선언해두지 않고 클로저 함수 패턴을 이용하여 내부 값이 변경될 때만 새로운 객체의 참조값을 주게끔 하면 어떨까? 생각해보았다.

// 어떤함수는 스타일 객체를 받아 이전과 달라지지 않으면 이전 객체(참조값이 변하지 않은) 그대로 전달하고
// 객체가 이전과 달라졌다면 달라진 객체를 반환하는 함수
// 메모이제이션 하는 함수겠지
<div className="small-card" style={어떤함수({backgroundColor: CARD_TYPE[cardType]?.color ?? '#e5e5e5' })} />

아래와 같은 패턴도 생각해보았지만, 훅을 어떤 엘리멘트의 prop에서 호출해버리는 게 일정한 훅의 호출을 지향하는 리액트 특성상 어울리지 않는 코드 패턴일것 같아 제외시켰습니다..

<div className="small-card" style={useMemo(()=>({ backgroundColor:CARD_TYPE[cardType]?.color ?? '#e5e5e5',}),[cardType])} />

2트

클로져 함수 만들기

아이디어는 간단합니다. 프로젝트 전역에서 사용되는 inline-style 객체들을 메모이제이션 한다!


export const { getMemoStyle } = (() => {
  const data = {};

  // 내부의 값이 변경되지 않았다면 이전에 저장해둔 스타일 객체 내보냄.
  // 결국 내부의 값이 변경되지 않느 경우에는 리렌더링이 발생하지 않겠지?
  return {
    getMemoStyle(key, style) {
      if (data[key] === undefined) {
        data[key] = style;
      }

      if (Object.keys(style).length !== Object.keys(data[key])) {
        // style의 내부가 바뀐 것이므로 업데이트
        data[key] = style;
      }

      if (Object.keys(style).some(styleKey => data[key][styleKey] !== style[styleKey])) {
        // style의 내부가 바뀐 것이므로 업데이트
        data[key] = style;
      }

      return data[key];
    },
  };
})();

사용하기

// 이렇게 하면 새로운 참조값을 갖는 객체가 전달되어 재조정되는 경우는 -> 내부 속성의 값이 변경될 때 만으로 한정되게 됨. 최적화가 가능
   <div
        className="small-card"
        style={getMemoStyle('small-card', {
          backgroundColor: CARD_TYPE[cardType]?.color ?? '#e5e5e5',
        })}
      >

확실히 이렇게 작성하면 지역변수를 선언할 필요도 없고, 내부 속성 값이 변경될 때만 새로운 객체를 전달할 수 있게되어 최적화도 할 수 있습니다.

하지만

  • 엘리먼트 별로 유니크한 키 값을 갖게하는 것, 이를 위한 코드 작성이 오히려 단점.(이를 호출하는 컴포넌트가 렌더링이 다시 될 때에도 계속 가지고 있을 수 있는 키)

  • 리액트의 재조정을 트리거하는 작업을 다른 유틸성 함수에게 위임하는 것이 옳을까?

결론
일단은 inline-style을 사용하는 곳이 4군데 밖에 없다는 점, 명확한 solution을 찾지 못했다는 점 때문에 현상 유지 시키기로 결정하였습니다.

하지만 이 과정에서

  • 객체로 전달되는 prop의 경우 내부 값의 변경이 발생하지 않았음에도 리렌더링될 수 있다는 점을 다시 한번 상기시키게 됨

  • React Element의 prop으로 전달되는 객체는 read-only 해진다. (스타일 객체의 내부 값을 변경해보려고 하니 에러를 보여주더군요.. Read-Only 한 객체를 수정할 수 없다는.. 그러한..)

을 깨달을 수 있었습니다.

다짐
명확한 솔루션을 찾는것 + React Hook을 prop에 inline으로 작성하는 것이 옳을까 고민해보기 + prop으로 전달되는 객체를 read-only하게 만드는 리액트의 코드를 찾아봐야겠다고 다짐함 ㅋㅋ..

`

profile
Frontend Ninja

6개의 댓글

comment-user-thumbnail
2022년 5월 8일

늘 탐구하고 고민하며 개발하는 준찌를 보면서 많이 자극받고 반성합늬다.......
저는 준찌한테 빨대 꽂겠습니다....ㅎ
이번주도 빠이팅~!~!~!

1개의 답글
comment-user-thumbnail
2022년 5월 9일

반가운 준찌! 건강하게 돌아와서 기뻐요.
인라인 스타일의 재렌더링 이슈와 리액트 엘리먼트에 prop으로 전달되는 객체는 readonly군요! 덕분에 항상 많이 배워요

1개의 답글
comment-user-thumbnail
2022년 5월 9일

코로롱으로부터 돌아온 준찌!
호오 인라인 스타일링이 이래서?!?! 신기방기

답글 달기
comment-user-thumbnail
2022년 5월 9일

준찌~~ 이제 아프지 않기로 약속 🔥

답글 달기