Container-Presenter
JavaScript ReactContainer / Presenter
Container / Presentational 패턴이란, 소스코드를 자바스크립트(기능)과 JSX(UI)로 나누는 방법을 의미한다.
/* 이 부분이 Container */
export default function UsernamePage() {
const [username, setUsername] = useState();
const handleChangeUsername = (event) => {
const username = event.target.value;
setUsername(username)
}
/* 이 부분이 Presenter */
return (
<div>
<label>Username</label>
<input type="text" onChange={handleChangeUsername}>
<div/>
)
}
파일 나누기
파일 구조는 아래와 같게 지정한다. 파일을 나눠도 실행될 때는 하나로 합쳐져서 실행될 수 있도록 한다.
├── parentFolder
│ ├── Username.container.js
│ ├── Username.presenter.js
~~~~~~~
~~~~~~~
│ ├── Username.queries.js // 등 다른 종속 파일들이 들어갈 수 있다
│ ├── Username.styles.js
각 파일당 코드 구조는 위의 코드를 각 부분에 맞게 위치시키면 된다.
/* Username.container.js */
import UsernameUI from "./Username.presenter" // import Presenter here
export default function Username() {
const [username, setUsername] = useState();
const handleChangeUsername = (event) => {
const username = event.target.value;
setUsername(username)
}
return (
<UsernameUI/>
)
}
/* Username.presenter.js */
export default function UsernameUI() {
return (
<div>
<label>Username</label>
<input type="text" onChange={handleChangeUsername}>
<div/>
)
}
Props
컴포넌트를 두개로 나누면서 데이터와 기능의 연결고리가 끊어지게 된다. 이를 연결해주는 것이 props의 역할이며, props란 부모 컴포넌트가 자식 컴포넌트에게 물려주는(단방향) 변수 및 함수를 의미한다. 부모 컴포넌트가 props를 물려줄 때는 객체로 묶어서 넘기게 된다. React Docs
/* Username.container.js */
import UsernameUI from "./Username.presenter" // import Presenter here
export default function Username() {
const [username, setUsername] = useState();
const handleChangeUsername = (event) => {
const username = event.target.value;
setUsername(username)
}
return (
/*
<input type="text" onChange={handleChangeUsername}
의 onChange 이벤트를 더이상 받을 수 없으므로 props로 전달해야 함.
*/
<UsernameUI changeUsername={handleChangeUsername}/>
)
}
/* Username.presenter.js */
/* Parent(container)에서 전달받은 handleChangeUsername는 props의 객체 아래로 들어옴 */
export default function UsernameUI(props) {
return (
<div>
<label>Username</label>
<input type="text" onChange={props.changeUsername}>
<div/>
)
}
+ 한 컴포넌트의 UI 및 기능을 한 파일에 담는 게 특징인 Vue에서는 아래와 같이 구현된다.
<!-- UsernameInput.vue -->
<template>
<div>
<label>Username</label>
<input :value="username" @change="$emit('update:username', $event.target.value)" />
</div>
</template>
<script>
export default { props: ['username'], emits: ['update:username'] }
</script>