도서 "더 괜찮은 웹 개발자가 되기 위한 리액트 스타일 가이드 (프런트엔드를 아우르는 사용자 중심의 모던 UI 컴포넌트 설계와 개발)"에서 UI 구현 + 프로젝트 구성 부분에 대해 학습한 내용 일부 정리+복습
표현
화면 위에서 GUI로 표시되므로 구조적인 관점에서 역할을 나누어 구현하는 방법. 어떤 UI를 화면에 표시할 것인가?
표현
에만 집중. 즉, 화면 표시 내용이 달라져서는 안됨.순수한 함수
여야 한다는 점이 중요함. 부작용이 없다는 의미는 함수의 실행에 다른 전역 변수나 정적 변수들에 영향을 주지 않는다는 의미Stateless Functional Components (SFC)
: 상태가 없는, 내부적으로 State를 가지지 않는 함수형 컴포넌트.import React from 'react'
const UserCard = (props) => {
return (
<div>
<p>{props.name}</p>
<p>{props.age}</p>
</div>
);
}
export default UserCard
import React from 'react'
const UserCard = (props) => {
return (
<div>
<p>{props.name}</p>
<button onClick={props.onClickFunction}>Click</button>
</div>
);
}
export default UserCard
import React from 'react'
import UserCard from './UserCard'
const UserCardWrapper = () => {
return (
<div>
<Usercard name="taro" onClickFunction={()=>{console.log("UserCard")}} />
</div>
);
}
export default UserCardWrapper
용기
(화물용) 컨테이너
표시를 제어할 용기구체적인 데이터나 동작을 자식 컴포넌트에 제공하는 컨트롤러
와 같은 역할을 담당한다.ItemContainer 컴포넌트 : 데이터를 가진 컨테이너
ㄴ MainTitle 컴포넌트 : 제목 표시
ㄴ ItemList 컴포넌트 : 실제 목록 출력 (props로 ItemContainer의 데이터를 전달 받음)
ItemContainer 컴포넌트는 데이터 관리
만 수행하므로 실제로 어떤 UI가 표시될 것인가는 신경쓸 필요가 없음. UI 표시는 자식 컴포넌트가 담당하므로 데이터를 전달하기만 하면 이 컴포넌트의 역할은 끝남.
import React, { Component } from 'react';
import MainTitle from './MainTitle';
import ItemList from './ItemList';
class ItemContainer extends Component {
constructor() {
super();
// 자신이 상태를 저장
this.state = {
items: ['Item 1', 'Item 2', 'Item 3', 'Item 4']
}
this.handleUpdateFlag = this.handleUpdateFlag.bind(this);
}
handleUpdateFlag() {
this.state.items.push("AAA");
this.setState({
items: this.state.items
});
}
render() {
// 자식 컴포넌트에 대해 데이터를 전달하기만 함
return (
<div>
<MainTitle text="My Items Page" url="https://www.example.com" />
<ItemList items={this.state.items} />
</div>
);
}
}
export default ItemContainer
추상화
되어 있다는 점에도 주목해야 함. 이전의 웹 페이지의 소스 코드에서는 HTML이나 CSS 코드가 복잡하게 얽혀 있으므로, 실제 어떤 요소를 화면에 표시하는가를 알려진 모든 코드를 읽고 이해해야 했지만 지금은 어떤 목적의 요소를 어떤 값으로 화면에 표시하는가가 간결하게 표현되며 각 요소의 구성 요소를 재빠르게 이해
할 수 있습니다.정리
Presentational 컴포넌트는 렌더링과 관련된 책임을 지고,
Container 컴포넌트는 데이터 구조나 데이터 흐름을 담당한다.
import React from 'react'
const ViewFlagValue = (props) => {
// 전달받은 데이터를 이용하여 화면만 표시
return <p>{props.flag ? '유효' : '무효'}</p>;
}
export default ViewFlagValue
import React from 'react'
const FlagSwitch = () => {
// 이 버튼을 클릭했을 때 Flag값을 바꾸고 싶음
return <button>Switch Flag</button>
}
export default FlagSwitch
import React, { Component } from 'react'
import FlagSwitch from './FlagSwitch'
import VieFlagValue from './ViewFlagValue'
class SwitchContainer extends Component {
constructor() {
super();
this.state = { flag: flase }
}
render() {
return (
<div>
<FlagSwitch></FlagSwitch>
<ViewFlagValue flag={this.state.flag}></ViewFlagValue>
</div>
)
}
}
export default SwitchContainer
설계상, 컴포넌트 안에 데이터를 가둔 형태로 State를 갖는 것을 허용
하는 것이 결과적으로는 전체 소스 코드를 더 잘 운영할 수 있게 한다. 이러한 State를 Local State
라고 한다.Presentational 안에서 아토믹 디자인에 따른 디렉토리 구조를 가지게 분류
src/index.js
src/container/header.js
src/container/footer.js
src/presentational/atoms/button.js
src/presentational/atoms/checkbox.js
src/presentational/molecules/seachbox.js
src/presentational/molecules/sharebutton.js
Container 안에서 아토믹 디자인에 따라 역할 분담을 수행하도록 분류
src/index.js
src/container/organisms/header.js
src/container/organisms/footer.js
src/container/templates/top.js
src/container/templates/404.js
src/presentational/atoms/...
src/presentational/molecules/...
특정 처리를 modules 디렉토리로 뽑아내도록 분류
src/index.js
src/components/container/...
src/components/presentational/...
src/modules/...
1 컴포넌트 1 디렉토리로 분류
src/button/index.js
src/button/button.css
src/button/button.spec.js
학습자료
💬 컴포넌트의 상태 관리(리덕스) 부분은 다른 프로젝트를 실습해보고 읽어볼 예정이다.