안녕하세요. 오늘은 React의 custom hooks에 대해 알아보고 직접 만들어보는 시간을 가져보도록 하겠습니다.
Custom hook이란?
요즘 React 개발 트랜드는 react hook을 적극 활용하는 것입니다. hook을 사용함으로 인해 class component 없이도 여러 state 값을 변경해줄 수 있게 되었고, 이는 React 개발자들이 function component를 통한 간결한 코드 작업을 할수있게끔 만들어주었습니다. useState, useEffect 등등 hook을 사용하는 것만으로도 코드가 훨씬 보기 좋아졌지만,반복되는 훅 활용 메소드들을 하나로 줄여줌으로써 더 간결하고 보기 좋은 코드를 만들 수 있는 것이 바로 custom hooks입니다.이름에서 알 수 있다시피 custom hook은 개발자 본인이 직접 hook을 만드는 것이죠.
그렇지만 중요한 포인트가 있습니다.custom hook의 이름은 무조건!!!! use로 시작해야합니다.이 점은 꼭 유념해주셔야 합니다.
사용 예제 코드
custom hooks 적용 전
Jsonplaceholder API를 사용하여 간단하게 구현해보도록 하겠습니다. 우선 UserList, UserDetail 컴포넌트를 생성했습니다. Jsonplaceholder에서 유저정보 10개를 받아 리스트로 보여주고 유저이름을 클릭하면 UserDetail page로 이동하는 아주 간단한 예제입니다.
UserList,UserDetail 컴포넌트에서 겹쳤던 fetch부분을 그대로 넣어주고 data를 return 해주면 끝입니다. url을 인자로 받고 해당 url을 useEffect의 의존성 배열로 넣어주면 custom hook이 원할때 잘 호출되겠죠??이제 UserList, UserDetail 컴포넌트가 어떻게 변경할 수 있는지 살펴볼까요??
custom hooks 적용 후
//UserList.js
import React from "react"
import { Link } from "react-router-dom"
import useFetch from "./hooks/useFetch"
function UserList() {
const userList = useFetch("https://jsonplaceholder.typicode.com/users")
return userList.map(user => (
<Link
to={`/${user.id}`}
key={user.id}
className="list-group-item list-group-item-action"
>
<div>{user.name}</div>
</Link>
))
}
export default UserList
//UserDetail.js
import React from "react"
import { useParams } from "react-router-dom"
import useFetch from "./hooks/useFetch"
function UserDetail(props) {
const { id } = useParams()
const userInfo = useFetch(`https://jsonplaceholder.typicode.com/users/${id}`)
return (
<div>
{userInfo.name}
<br />
{userInfo.email}
<br />
{userInfo.phone}
</div>
)
}
export default UserDetail
어떤가요??단 한줄로 useEffect와 useState 그리고 fetch 함수를 대체할 수가 있어졌습니다.이전 코드보다 훨씬 간단해졌고 custom hooks의 네이밍이 잘되어있다는 가정하에 코드 가독성도 훨씬 높아지지 않았나요?? 지금은 fetch함수를 사용하는 component가 2개밖에 없지만 fetch함수를 사용하는 컴포넌트가 더 많으면 많을 수록 우리의 custom hooks는 그 힘을 발휘할 것입니다 ㅎㅅㅎ
마무리
이렇게컴포넌트 로직을 뽑아내서 정의한 후 간편하게 호출할 수 있다는 것이 custom hooks의 정말 큰 장점이 아닐까 생각이됩니다. 이 밖에도 여러개의 input들이 존재하고 각각 여러개의 state 값을 control할 때에도 useInput이라는 custom hooks를 사용하여 코드를 간단하게 만들 수 있을겁니다. 아니면 user 정보를 useAuth라는 custom hooks를 만들어 그때그때 편하게 호출할 수도 있겠죠? custom hooks를 좋은네이밍과 더불어 사용하면 코드의 가독성을 높이고 짧고 간결한 코드를 작성할 수가 있을겁니다.
props가 업데이트될 때의 과정입니다. 업데이트되기 전에 업데이트가 발생하였음을 감지하고, componentWillReceiveProps 메소드가 호출됩니다. 그 후 shouldComponentUpdate, componentWillUpdate가 차례대로 호출된 후, 업데이트가 완료(render)되면 componentDidUpdate가 됩니다. 이 메소드들은 첫 번째 인자로 바뀔 props에 대한 정보를 가지고 있습니다.componentDidUpdate만 이미 업데이트되었기 때문에 바뀌기 이전의 props에 대한 정보를 가지고 있습니다.
componentDidUpdate(prevProps, prevState) { // 이전 props, state에 대한 정보
if (prevProps.todos.length !== this.props.todos.length) {
// 이전 todo리스트의 길이가 달라지면(추가,삭제) 상태변화
this.setState({
dataSource: this.state.ds.cloneWithRowsAndSections(
_.groupBy(this.props.todos, 'createdAt'),
),
})
}
if (prevState.isTodoList !== this.state.isTodoList) {
// 탭 이동
if (!this.state.isTodoList) { // 완료된 탭일 때,
this.setState({ // 완료된 탭만 필터된 datasource
dataSource: this.state.ds.cloneWithRowsAndSections(
_.groupBy(_.filter(this.props.todos, (todo) => todo.isDone), 'createdAt'),
),
})
} else {
this.setState({
dataSource: this.state.ds.cloneWithRowsAndSections(
_.groupBy(this.props.todos, 'createdAt'),
),
})
}
}
}