์ปดํฌ๋จผํธ์ ๋ก์ง์ ์ฌ์ฌ์ฉํ๊ธฐ ์ํด์ ๊ณ ์ฐจ ์ปดํฌ๋ํธ(Higher-Order Components)๋ฅผ ์ฌ์ฉํด์์ต๋๋ค. ํ์ง๋ง custom hook์ผ๋ก ๋ ๊ฐํธํ๊ฒ ์ํ๊ด๋ฆฌ ๋ก์ง์ ๊ณต์ ํ ์ ์์ต๋๋ค.
// CommentList.js
class CommentList extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {
comments: DataSource.getComments()
};
}
componentDidMount() {
DataSource.addChangeListener(this.handleChange);
}
componentWillUnmount() {
DataSource.removeChangeListener(this.handleChange);
}
handleChange() {
this.setState({
comments: DataSource.getComments()
});
}
render() {
return (
<div>
{this.state.comments.map((comment) => (
<Comment comment={comment} key={comment.id} />
))}
</div>
);
}
}
์ ์ฝ๋๋ ์ธ๋ถ๋ก๋ถํฐ ๋ฐ์ดํฐ๋ฅผ ๊ตฌ๋ ํ์ฌ ๋๊ธ๋ชฉ๋ก์ ๋ ๋๋งํ๋ CommentList ์ปดํฌ๋จผํธ ์ ๋๋ค. ๊ทธ๋ฆฌ๊ณ ๋ฐ์๋ ๋ธ๋ก๊ทธ ํฌ์คํธ ๊ตฌ๋ ์ ํ๊ธฐ์ํด ๋น์ทํ ํจํด์ผ๋ก ์ปดํฌ๋ํธ๋ฅผ ์์ฑํ๊ฒ ๋ฉ๋๋ค.
// BlogPost.js
class BlogPost extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {
blogPost: DataSource.getBlogPost(props.id)
};
}
componentDidMount() {
DataSource.addChangeListener(this.handleChange);
}
componentWillUnmount() {
DataSource.removeChangeListener(this.handleChange);
}
handleChange() {
this.setState({
blogPost: DataSource.getBlogPost(this.props.id)
});
}
render() {
return <TextBlock text={this.state.blogPost} />;
}
}
์ ์ํฉ์ HOC๋ฅผ ์ฌ์ฉํด ์ค๋ณต์ ์ ๊ฑฐ ํ ์๋ ์์ง๋ง custom hook ์ ๋ง๋ค์ด์ ์ฒ๋ฆฌ ํ ์ ์์ต๋๋ค. custom hook์ผ๋ก ์ฒ๋ฆฌ์ HOC๋ณด๋ค ์ฅ์ ์ด ์์ต๋๋ค.
HOC๋ฅผ ์ฌ์ฉํ๋ฉด ๊ฒฐ๊ตญ์ ํ๋์ ์ปดํฌ๋ํธ๋ฅผ ์์ฑํด์ ๊ฐ์ธ์ผ ํฉ๋๋ค. ์ด๋ ๊ฒ ๊ฐ์ธ๋ค ๋ณด๋ฉด wrapper hell์ด ๋ฐ์ํ๊ฒ ๋ ๊ฒ์ ๋๋ค. ๊ทธ๋ฆฌ๊ณ hook์ ๋ง๋ค๋ฉด ๋ณ ๋ค๋ฅธ ์์ ์์ด React ํจ์์์์๋ ํธํ๊ฒ ์ฌ์ฉ์ด ๊ฐ๋ฅํด ์ง๋๋ค. ์ด์ custom hook์ ๋ง๋ค์ด์ ์ ์์ ๋ฅผ ์ข ๋ ํธํ๊ฒ ๋ง๋ค์ด ๋ด ์๋ค.
// SubscribeData.js
function useSubscribeData({ fetchData, id }) {
const [data, setData] = React.useState(null);
const handleChange = React.useCallback(() => {
setData(fetchData(id));
}, [fetchData, id])
React.useEffect(() => {
DataSource.addChangeListener(handleChange);
return () => {
DataSource.removeChangeListener(handleChange);
}
}, [handleChange])
React.useEffect(() => {
setData(fetchData(id));
}, [fetchData, id])
return data;
}
useSubscribeData.defaultProps = {
id: '',
}
์ ์ฒ๋ผ custom hooks์ ๋ง๋ญ๋๋ค. custom hooks ์์์๋ ๋๊ฐ์ด useEffect๋ useState๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์ด์ ๋ง๋ SubscribeData hook์ ์ฌ์ฉํด ๋ด ์๋ค. ๋ฆฌํด์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ๋ณด๋ผ ์๋ ์์ง๋ง ํจ์๋ฅผ returnํด์ state๋ฅผ ๋ณ๊ฒฝ ํ๋๊ฒ๋ ๊ฐ๋ฅํฉ๋๋ค.
// CommentList.js
const CommentList = () => {
const fetchData = React.useCallback(() => {
return DataSource.getComments();
}, []);
const comments = useSubscribeData({
fetchData: fetchData
});
return (
<div>
{comments.map(comment => (
<div comment={comment} key={comment.id} />
))}
</div>
);
};
// BlogList.js
const BlogList = ({ id }) => {
const fetchData = React.useCallback(() => {
return DataSource.getBlogPost(id);
}, [id]);
const post = useSubscribeData({
fetchData: fetchData,
id: id
});
return <div>this is post!!</div>;
};
์ด์ ์์ฝ๊ฒ component๋ฅผ ์ถ๊ฐํ์ง ์์๋ ์ํ๊ด๋ฆฌ ๋ก์ง์ ์ปดํฌ๋ํธ๋ผ๋ฆฌ ๊ณต์ ๊ฐ ๊ฐ๋ฅํฉ๋๋ค.