Day of Nomad

리액트 디자인 패턴 React Design Pattern 본문

Develop/React

리액트 디자인 패턴 React Design Pattern

DeveloperYong 2018. 7. 1. 18:35

React 디자인 패턴

  Container + Pressenter Pattern


소프트웨어를 디자인할때 function class를 작성하는 여러가지 패턴이 있다.


책도 많고, 디자인 패턴 종류도 여러가지 있다.


또 회사마다도 쓰는 패턴 종류도 각양 각색이다.


CSS를 작성할때 BEM, smax 등 여러 이론과 방법론이 있는 것 처럼...



우선 개인적으로 가장 선호하는 패턴이자 많은 곳에서 쓰여지고 있는


Container presneter Pattern에 대하여 알아보겠다.




Goal

실습 목표!




Call an API to get the latest blog posts.


Show a 'loading' status in the meantime.


When the call to the API is resolved, render the blog posts.


최근 블로그 포스팅의 API를 불러오고, 진행될 동안 '로딩 중'을 띄우는 것.


해당 작업이 끝나면, 블로그 포스팅을 렌더링 할거다. (블로그의 제목)





우선 패턴 사용 없이 진행해 보자.



// src/components/blog/Blog.js


import React, {Component} from 'react';

class Blog extends Component {
state = {
loading: true
};
componentDidMount() {
fetch('/api/blog')
.then(res => res.json())
.then(
posts =>
this.setState({
loading: false,
posts
}),
error => this.setState({
loading: false,
error
})
);
}
render() {
if ( this.state.loading){
return <div>Loading...</div>;
} else {
this,state.posts.map(post => <div key={post.id}>{post.title}</div>);
}
}
}


6줄: state 는 로딩 true

10~ 24줄: Component가 마운트되면 api를 부르고, 완료되면,

포스팅을 불러오고, 로딩 : false하고, 포스팅을 올린다.

에러가 있으면 loading: false하고 에러를 보여준다.

25~ 31줄: render function 에서는 state가 로딩이면, Loading 문구를 띄움.


결국에는 데이터를 불러오고, 블로그 포스팅을 보여주는 작업을 하는 거다.

그런데 크게 보았을때 이는 좋지 않다. 같은 장소에서 데이터를 불러오고 보여주면 안된다.

왜냐하면 presentaion과 logic을 분리 해야되기 때문.


여기까지가 보통 리액트를 짜는 방법.


이를 위해 등장한 것이 디자인 패턴!

container + presenter 방법.


Container컴포넌트 + Presenter컴포넌트



Container

Logic : API Requests, errors etc...


Presenter

Data comes from props. No logic. Only UI


container 컴포넌트는 논리, logic과 api를 갖고 있고,

presenter 컴포넌트은 UI, 사진 등...을 갖고 있다.


container 컴포넌트부터 살펴보자.


// src/components/blog/BlogContainer.js

import React, {Component} from 'react';
import Blog from './Blog';

class BlogContainer extends Component {
state = {
loading: true
};
componentDidMount() {
fetch('/api/blog')
.then(res => res.json())
.then(
posts =>
this.setState({
loading: false,
posts
}),
error => this.setState({
loading: false,
error
})
);
}
render() {
<Blog { ...this.state} />;
}
}

export default BlogContainer;



기존의 Blog.js와 거의 다 똑같은데,

차이점은 이 컴포넌트는 '블로그 컨테이너'인 것이다.

블로그 컨테이너는 블로그 컴포넌트를 render, return 한다.

(state를 유지하면서...) 로딩, 포스트, 에러를 렌더할 것이다.



자, 그러면 presenter에서는 props에서 데이터가 나오고, 로직이 없고,

오직 UI만 이야기한다. state에 대한 이야기가 없다.

블로그 컨테이너가 state 변화를 이야기한다.

presenter는 logic, 논리 이야기는 없다. 오직 유저 인터페이스만 이야기 할 뿐.!



그러면 presenter 컴포넌트는 이렇게 생겼다.


// src/components/blog/Blog.js

import React from 'react';

class Blog extends Component {
_renderLoading = () => {
return <div>Loading...</div>
};

_renderError = () => {
return <div>Error occurs! Please try again.</div>;
};

_renderPosts = () => {
const { posts } = this.props;
return posts.map(post => <div key={post.id}>{post.title}</div>);
};

render() {
if(this.props.loading) {
return this._renderLoading();
} else if(this.props.posts) {
return this._renderPosts();
} else {
return this._renderError();
}
}
}

export default Blog;



props에서 데이터를 갖고오고, state 변경 없고,

로딩중이면, 렌더 로딩 함수를 불러와서

로딩 중이 아니면 props에 post가 있으면 포스팅을 렌더하고,

로딩도 아니고, 포스도 아니면 에러 출력. '에러 발생! 다시 시도하세요.'


보다시피 기존보다 더 정리되어 있다. state 변경 없고, api 부르는 것도 아니다.

props에서 데이터 가져오는 것 뿐.





결론.


두가지를 이해하자.

1. 컨테이너는 state도 이해하고, api. 리덕스를 부를 수 있다.

 state를 변경. 리덕스 액션 불러오고, 액션 디스패치하고,, 등등


2. 프레젠터에서는 props에 따라 데이터가 어떻게 보이는지 알려준다.


이것이 Container Presenter Pattern이다.


데이터 그리고 데이터 출력 방법을 분리하는 것!






더 자세한 사항은 아래 링크를 참고하세요!

https://levelup.gitconnected.com/react-component-patterns-ab1f09be2c82 

Comments