리액트 Higher-order Component(HOC)
코드를 작성하다보면, 자주 반복해서 작성하게 되는 코드들이 있다. 우리는 주로 그러한 것들을 함수화해서 재사용 하곤 한다. 컴포넌트 또한 비슷하다. 같은 UI 관련 코드가 재사용 될 수 있다면 우리는 컴포넌트를 만들어서 컴포넌트를 재사용한다.그런데 컴포넌트 기능 상에도, 자주 반복되는 코드들이 나타날 수 있다. 소프트웨어 개발 원리 중에서 DRY 라는 개념이 있다. - 같은 작업을 반복하지 마라 (Don't repeat yourself)
리액트 컴포넌트를 작성하게 될 때 반복될 수 있는 코드들은, HOC를 만들어서 해결해줄 수 있다. HOC는, 하나의 함수인데, 함수를 통하여 컴포넌트에 우리가 준비한 특정 기능을 부여한다. 직접 만들어볼 때 까지는 감이 잡히지 않을 수도 있다. 직접 한번 만들어보자.
*코드 : https://codesandbox.io/s/qzj9kw265w
# 반복되는 코드 발견하기
Post.js 코드를 읽어보자.
import React, { Component } from 'react';
import axios from 'axios';
class Post extends Component {
state = {
data: null
}
async initialize() {
try {
const response = await axios.get('https://jsonplaceholder.typicode.com/posts/1');
this.setState({
data: response.data
});
} catch (e) {
console.log(e);
}
}
componentDidMount() {
this.initialize();
}
render() {
const { data } = this.state;
if (!data) return null;
return (
<div>
{ JSON.stringify(data) }
</div>
);
}
}
export default Post;
이 컴포넌트 에서는, 특정 주소에 GET 요청을 날리고, 결과물을 state의 data안데 담는다. 그래고, 해당 data를 JSON 형태로 그대로 렌더링 해준다.
Comment.js도 확인해보자.
import React, { Component } from 'react';
import axios from 'axios';
class Comments extends Component {
state = {
data: null
}
async initialize() {
try {
const response = await axios.get('https://jsonplaceholder.typicode.com/comments?postId=1');
this.setState({
data: response.data
});
} catch (e) {
console.log(e);
}
}
componentDidMount() {
this.initialize();
}
render() {
const { data } = this.state;
if (!data) return null;
return (
<div>
{JSON.stringify(data)}
</div>
);
}
}
export default Comments;
그냥 거의 똑같다. 우선, 이렇게 반복되는 코드를 발견하는것이 첫번째 단추이다.
# HOC 작성하기
우리는 이 반복되는 코드를 없애기 위해서 하나의 함수를 작성한다. 주로 HOC 의 이름을 만들땐 with____ 형식으로 짓는다. 예를들어, 우리는 웹요청을 하는 HOC를 만들테니 withRequest 라고 지어주도록 하겠다.
HOC의 원리는, 파라미터로 컴포넌트를 받아오고, 함수 내부에서 새 컴포넌트를 만든 다음에 해당 컴포넌트 안에서 받아온 컴포넌트를 렌더링하는 것이다. 그리고, 자신이 받아온 props 들은 그대로 파라미터로 받아온 컴포넌트에게 다시 주입해주고, 필요에 따라 추가 props도 넣어준다. (예를 들어 우리의 경우엔 웹 요청 결과물이다.)
우선 HOC의 틀을 작성해보자.
withRequest.js
import React, { Component } from 'react';
const withRequest = (url) => (WrappedComponent) => {
return class extends Component {
render() {
return (
<WrappedComponent {...this.props}/>
)
}
}
}
export default withRequest;
위 코드를 보면, 함수에서 또 다른 함수를 리턴하도록 했다. (url, WrappedComponent) 형식이 아니라, (url) => (WrappedComponent)로 한 이유는, 나중에 여러개의 HOC를 합쳐서 사용하게 될때 더욱 편하게 사용하기 위함이다. - compose같은 함수를 통하여 호출을 간소화 할 수 있다.
그럼, HOC에 기능을 붙여보자.
import React, { Component } from 'react';
import axios from 'axios';
const withRequest = (url) => (WrappedComponen) => {
return class extends Component {
state = {
data: null
}
async initialize() {
try {
const response = await axios.get(url);
this.setState({
data: response.data
});
} catch (e) {
console.log(e);
}
}
componentDidMount() {
this.initialize();
}
render() {
const { data } = this.state;
return (
<WrappedComponent {...this.props} data={data}/>
)
}
}
}
export default withRequest;
axios를 통하여 받은 data를 파라미터로 받은 컴포넌트에 넣어주도록 설정을 했다.
# HOC 사용하기
HOC를 다 만들었다면, 사용하는 일만 남았다. Post와 Comments에서 한번 사용해보자.
Post.js
import React, { Component } from 'react';
import withRequest from './withRequest';
class Post extends Component {
render() {
const { data } = this.props;
if (!data) return null;
return (
<div>
{ JSON.stringify(this.props.data) }
</div>
);
}
}
export default withRequest('https://jsonplaceholder.typicode.com/posts/1')(Post);
컴포넌트를 내보낼때 이렇게 사용하면 된다.
혹은,
const PostWithData = withRequest('https://jsonplaceholder.typicode.com/posts/1')(Post)
export default PostWithData;
의형식으로 해도 된다.
Comments도 마찬가지로 withRequest를 사용해보자.
Comments.js
import React, { Component } from 'react';
import withRequest from './withRequest';
class Comments extends Component {
render() {
const { data } = this.props;
if (!data) return null;
return (
<div>
{JSON.stringify(data)}
</div>
);
}
}
export default withRequest('https://jsonplaceholder.typicode.com/comments?postId=1')(Comments);
# 정리
이렇게 HOC를 사용함으로서, 반복되는 코드들이 많이 사라졌다. 이렇게 웹요청을 하는 외에도, LifeCycle 메소드를 붙여준다던지, Redux에서 특정 값을 받아와서 주입해준다던지, 다국어지원을 한다던지 여러가지 일들을 할 수 있다.
recompose라는 라이브러리는, 페이스북 개발자가 만든 유용한 HOC 컬렉션 라이브러리인데, 활용하면 매우 쓸모있다. 종류는 굉장히 많은데, 이제 HOC가 어떤 역할을 하는지 알았으니, recompose의 API 문서를 쭉 훑어보면 어떤 것들을 할 수 있는지 감을 잡을 수 있다.
출처 : https://velopert.com/3537
컴포넌트에 날개를 달아줘, 리액트 Higher-order Component (HoC) | VELOPERT.LOG
리액트 Higher-order Component (HOC) 코드를 작성하다보면, 자주 반복해서 작성하게 되는 코드들이 있습니다. 우리는 주로 그러한 것들을 함수화하여 재사용 하곤 하죠. 컴포넌트 또한 비슷하죠. 같은 UI 관련 코드가 재사용 될 수 있다면 우리는 컴포넌트를 만들어서 컴포넌트를 재사용합니다. 자, 그런데 컴포넌트 기능 상에서도, 자주 반복되는 코드들이 나타날 수 있습니다. 소프트웨어 개발 원리 중에서 DRY 라는 개념이 있죠 – 같은 작업을
velopert.com
'JavaScript > React.js' 카테고리의 다른 글
| 리액트 16.3 Context API 파헤치기 (0) | 2019.04.22 |
|---|---|
| Reselect를 이용하여 React와 Redux 최적화하기 (0) | 2019.04.17 |
| Redux (0) | 2019.04.09 |
| VELOPERT 리액트 강의 (0) | 2019.04.03 |
| webpack 설정 (0) | 2019.04.01 |