Card-app / 지난 한 달의 복습

jh_leitmotif·2021년 12월 27일
0

Frontend 개인 공부

목록 보기
16/24

개요

지난 한 달간 React를 학습하면서

개인적으로 인상깊게 학습했던 것들을 정리하고자 쓰는 포스팅입니다.

구현 화면

일전에 인스타그램을 클론코딩했을 때에는 flex 속성을 적극적으로 사용했었습니다.

그것은 피드가 스크롤을 통해서 내려가거나, 올라가는 수직적인 구조였기 때문에

flex-direction : column

을 사용하거나, block속성으로 차곡차곡 쌓기만 하면 되었는데

여러 Commerce 페이지들은 Grid 형태를 사용하는 경우가 많습니다.

저만 그런건지는 모르겠지만, 인스타그램은 웹보다는 모바일에 익숙합니다.
그 경향에 따라 엄지 손가락으로 스크롤 다운하거나, 업하는 등의 동작에 대해
그러한 구조를 가지고 있지 않나 생각해봅니다. 트위터같은 것도 마찬가지구요.

따라서 이번 복습겸 만드는 App은 Grid를 사용하게 되었습니다.

Grid

Grid :: 격자.

말 그대로 '격자' 무늬입니다. 배열 형태라고 할 수도 있을 것 같아요.
학창시절, 이 무늬로 된 모눈종이로 수업시간에 오목을 뒀던 기억이 있습니다 ㅋㅋ

아무튼, Grid는 flex를 사용했던 것과 마찬가지로 작동합니다.

.container{
 display:grid;
 .containerChild{
 	~
 }
}

위와 같이 부모가 되는 element에 grid 속성을 주면

하위 자식 요소들이 세팅에 따라 배치되는 방식입니다.

grid-template-columns: 30% 30% 30%;
column-gap: 5%;
grid-template-rows: 30% auto;
row-gap: 2.5%;

grid-template-columns는 쉽게 말해, 몇 열로 만들 것인지를 결정합니다.

위처럼 30%~ 로 3개를 해두면 자식 요소가 3개씩 나누어 1개의 열을 차지한다는 의미입니다.

grid-template-columns: repeat(3,30%)

위처럼 repeat를 사용해 더욱 줄여 표현할 수 있습니다.

마찬가지로 grid-template-rows는 몇 행으로 이루어지느냐? 와 유사한 속성인 듯 합니다. repeat도 사용가능하구요.

또한 auto를 통해 동적으로 반응하기도 합니다.

다만 이런 것을 하나하나 정해주기에는 길이도 길어지고, 하는 부분이 있어서

auto를 섬세하게 활용해야겠다.. 라는 생각이 들었고

grid-template-columns:repeat(3,1fr)

grid에서는 fr이라는 단위를 사용할 수 있습니다.

flex에서 flex를 차지하는 크기(?)를 의미한다고 이해한 flex-basis처럼

fr은 현재 grid 구조에서 남은 공간에 맞게 크기를 결정해줍니다.

즉, 굳이 static한 값이나 %로 상대적인 값을 생각하기보다는

fr과 auto를 잘 사용하면 보다 반응형으로 잘 설계할 수 있겠구나 라는 생각이 듭니다.

설계 구조

CRA로 작성된 APP입니다.
그러니까... root와 index, router는 쿨하게 생략합시다.

이 card-app은 단순히 마크업 언어에 모든 것을 집어넣지 않습니다.

mockup data로서 활약하는 cardData.json으로부터 먼저 몇개의 카드가 있는지 받아온 다음

그 length만큼 여러 개의 Card들을 렌더링합니다.

또한 각각의 Card들은 그들의 id를 통해 내용을 받아와 렌더링하게 됩니다.

1번 카드의 id = '1'
2번 카드의 id = '2'
3번 카드의 id = '3'
setCardContent(data[eachCardData.id])
...... 
즉 mockupdata에서 1에 해당하는, 2에 해당하는, 3에 해당하는
각기 다른 데이터를 받아서 렌더링해줍니다.

여기에서 한 가지 고려해야될 부분이라고 생각한 것은

결국 위와 같은 방식을 사용한다면 각각의 카드가 렌더링될 때마다

서버에 request를 날릴 것이고, 곧 stress로 이어질 것이다! 라는 것입니다.

잠깐 흑역사를 들고와보았습니다 😅😅😅

위의 경우엔 card-app과는 사뭇 다릅니다.

1. /Store/1 URL에 접근한다.
2. 렌더링될 때 1번 id부터 10번 id까지의 데이터를 렌더링한다.
3. 여기서, 각각의 element를 click하여 해당 상세 페이지로 들어가면
4. 그제서야 해당 element의 데이터를 가지고 서버에 request되면서
5. contents를 볼 수 있다.

즉, 해당 페이지에서는 1번의 서버 요청을 통해 10개의 이미지를 그렸고

이미지를 클릭해야 해당 element의 id를 통해 서버에 요청이 진행되는 방식입니다.

당장은 한번에 각각 다른 내용을 불러오고 싶어 카드 각기 1개의 req을 날리는 구조로 작성되기는 했지만

추후 페이지 설계시 꼭 고려해야할 사항으로 노트합니다.

예를 든다면, contents 부분에 '불러오기' 문자열을 넣어두고

해당 문자열에 onClick을 하여 그때서야 fetch 한다거나하면 될 거라고 생각합니다.

카드 동작 화면

각 카드는 전달받은 ID를 이용해 mockup data에서 컨텐츠를 가져옵니다.

위와 같이 독립적인 ID를 이용하므로 각자 자신의 것을 가져올 수 있습니다.

뿐만 아니라,

위와 같이 최상위 부모 컴포넌트에서 map으로 그려지기 때문에

각 카드는 하나의 독립적인 페이지로서 기능하면서, 예를 든다면

1번 카드의 input은 1번 카드의 body 부분에만 적용되는 것입니다.

유효성 검사

위의 input에 입력할 때마다 '게시' 글자의 비활성화 여부가 결정됩니다.

사실 처음엔

useEffect(()=>{
 if (ID.length>6 && PW.length>6) setDisValue(false)
 else setDisValue(true)
},[ID,PW])

이런 방식으로 컨트롤하는 것을 생각했지만

결국 state가 바뀔 때마다 렌더링이 된다는 부분을 생각한다면 굳이 effect를 쓸 필요가 없었습니다.

그냥 간단하게 상수로 boolean 변수를 하나 선언해주고

마크업 언어의 disabled 속성에 해당 변수를 넣어주기만 하면 더욱 깔끔한

방식으로 되었습니다.

브라우저 reduce

통념적인 브라우저 resizing event는 다음과 같습니다.

window.addEventListener('resize', handleResize)
return = () =>{
 window.removeEventListener('resize',handleResize)
}

여기서 handleResize에 의도하는 동작을 작성하면 되는데,

현재 구현한 카드 앱은 브라우저의 크기가 줄어들 때 '등록' 버튼이

세로로 뭉개지는 현상이 있었기에 폰트 사이즈를 줄인다거나, 버튼이 차지하는 width를 늘려줄 필요가 있었습니다.

handleResize(){
 if (window.innerWidth>x) btn.style.fontSize=2em
}

간단히 바닐라 js를 생각해보면 위처럼 구성될텐데, 이것은 React 스럽지 않습니다.

따라서 단순히 기준이 될 static 값을 두고, 해당 값보다 작거나, 혹은 크거나의 여부에 따라 true, 또는 false를 Card 컴포넌트로 넘깁니다.

Card 컴포넌트는 전달받은 props 값인 isWindowReduced 값의 여부에 따라

className에 reduce의 포함 여부를 확인하고

innerWidth를 썼다면 브라우저가 resize될 때마다 이벤트가 발생했을 텐데

단순히 true or false로만 생각하게 되므로 그만큼 렌더링의 횟수가 줄어듭니다.

불가피한 것이 아닐까? 라고 생각했던 영역 중 하나였지만

생각보다 간단하면서도 목마름을 해소하는 중요한 발견이었습니다.


마무리

적고 보면 크게 많은 부분은 아니나

기본에 명령형에 매몰되어 있던 부분을 되돌아보고, 고칠 수 있었던 중요한 한 달이었습니다.

profile
Define the undefined.

0개의 댓글