코드 캠프 08일차) 폴더 구조를 잡아보자!

민겸·2022년 9월 5일
0

코드캠프_FE09

목록 보기
5/28

동기분이 찍어준 설정샷 ㅋ

오늘 밤부터 태풍(힌남노)이 심해진다고 해서 오늘 은 좀 일찍 갈까 고민중...
근데 왜 힌남노일까.. 힌색 남색 노란색인가? ㅎㅎ................ㅇㅅㅇ

  1. Container / Presenter
  2. Props

주소 설계

주소 설계가 중요한 이유
주소만 가지고도 어떤 페이지인지 알 수 있으면 좋은 그런게 있다...?
없는 것보다는 훨씬 낫다. 나중에 따로 찾아보자..

동적 라우팅에서 폴더 이름 설정을 [변수명] 으로 설정하는 이유
REST 와 관련이 있다. -> 가독성 때문인가?

Restful

GET    /boards
POST   /boards
PUT    /boards
DELETE /boards 

여러 컨텐츠를 담고 있으므로 s를 붙여 복수형으로 작성
후, 개별 컨첸츠를 접근하려면 /로 다시 접근

GET    /boards/:id

1. Container / Presenter 패턴

Container and Presentational은 무엇인가?

  • 리액트의 디자인 패턴 중 하나이다.
  • 로직을 수행하는 컴포넌트와 UI를 구현하는 컴포넌트로 분리된다는 것이 핵심인 디자인 패턴이다.

Container

  • 내부 로직과 관련이 있는 컴포넌트를 Container 라 부른다.
  • 마크업이나 스타일과 관련이 없고 오직 로직만을 구현한 뒤 Presentional 컴포넌트에 props를 넘겨주기만 한다.

Presentation

  • 마크업 그리고 스타일링과 관련이 있는 컴포넌트를 Presenter 라 부른다.
  • 로직과는 관련이 없고 마크업 + 스타일링을 담당하며 UI 구현과 관련된 상태를 가지기도 하지만 그 외 내부 로직의 상태와 관련된 것들은 전부 Container로부터 props로 전달받아 변경시킨다.

장점

  • UI와 로직이 잘 구분되어 있어서 관심사 분리가 잘 되고 각각의 유지 보수가 수월해진다.
  • UI가 내부 로직과는 관련이 거의 없는 상태가 대부분이기 때문에, 재사용성이 매우 높다.

단점

  • 내부 로직과 마크업을 분리하는 만큼 파일이 많아진다.
  • 파일이 많아지는 만큼 depth가 깊어지고 props drilling이 발생하는 불편함이 생긴다.
  • props drilling이 잦아지면, props 자체를 한 번에 보고 파악하기 어려워진다.

효율적인 폴더 구조에 대하여

5000만 줄의 코드가 작성되어있는 한 파일이 있다고 생각해보자.
그 많은 코드 내에서 하나의 기능(함수나 변수)을 찾아야 할 때 어떻게 찾을 것인가?
Ctrl + F ? 변수 또는 함수명을 잘 지어서 ? 파일 내의 코드량이 많으면 이러한 방법들도 크게 도움이 되진 않을 것이다.


이런 문제들을 해결하기 위해 나온 폴더 구조 패턴이 있는데 바로 그것이 Container / Presenter 패턴이다.
리액트의 JSX로 예로 들면, 하나의 파일의 컴포넌트 내에 로직 작성 부분과 렌더링 부분을 각각의 파일로 나눠주는 것이다.컨테이너 파일에는 UI 로직이 들어가고 프레젠터 파일에는 Rendering 로직이 들어간다.

여기서 의문점이 생겨야 한다.

두 파일은 어떻게 연결할 것이며, 한 컴포넌트 내에서는 변수들이 같은 블록 범위에 있기 때문에 바로 사용할 수 있는데 이렇게 나눠버리면 어떻게 연결할 것인가?

좋은 지적이다.

두 파일을 연결하는 부분은 그 부분에 대해 따로 작성한 글이 있다. 그 부분을 살펴보길 바란다. (import / export)

2. props

두 컴포넌트 간에 변수를 이용할 수 있게 해주는 바로 그 부분을 해결해주는 것이 props이다. props는 부모 컴포넌트에서 자식 컴포넌트로 단방향으로 전달되는 데이터(변수나 함수)를 말한다. 이 props는 함수형 컴포넌트에서 다음과 같이 작동한다

import MyAppUI from 'MyAppUI가 있는 경로';

const MyApp = () => {
  	const sayHi = "hi!";
	return <MyAppUI aaa={sayHi} />
}
export default MyApp;

부모 컴포넌트인 MyApp에서 sayHi변수에 값을 저장한 다음 자식 컴포넌트인 MyAppUI에 원하는 이름에 담아서 리턴한다.

const MyAppUI = (props) => {
	return <div>{props.aaa}</div>
}
export default MyApp;

자식 컴포넌트인 MyAppUI에서 인자로 props를 받으면 props.aaa와 같은 형식으로 부모에서 선언한 sayHi변수를 가져와서 값을 불러올 수 있다.

이것을 container presenter 폴더 구조에 적용시키면 UI와 Logic의 확실한 분리가 가능해진다.

다시 폴더 구조 얘기로 돌아가보면 하나의 기능을 만들 때 해당 기능을 뜻하는 폴더를 만들고 폴더 밑에 그 기능의 렌더링 로직을 담은 파일과 UI 로직을 담은 파일로 나누고 아래와 같이 각각 container와 presenter로 파일명을 지어주면 된다.

src/commons
src/components
src/components/commons
src/components/units

한 번 쓰는 컴포넌트 units 폴더에!
두 번 이상 쓰는 컴포넌트 commons 폴더에!

이렇게 세세하게 나누면 나눌 수록 나중에 관리하기가 편해지고, 각 파일들의 코드량이 줄어들게 된다. 물론 그만큼 파일 수와 폴더 수는 많아지겠지만 원하는 부분을 찾을 때 훨씬 편할 것이다.


props를 사용해서 이벤트 핸들러와 state들을 자식 컴포넌트로 옮기다 보니... 이벤트 핸들러를 하나로 통일하고, state들을 하나의 객체로 묶어서 저장한 게 신의 한수였다는 생각이 든다... 이래서 리팩토링하는구나.. 나중엔 어차피 상태 관리 라이브러리를 사용하게 될테니까 딱히 객체로 묶어서 state들을 관리할 일은 더 없겠지만 그래도 과거의 나.. 칭찬해..

왜 확장성을 고려하며 코드를 짜는지 확실하게 느끼게 된 오늘이다.

profile
기술부채상환중...

0개의 댓글