[10분 테코톡] React Hooks

흑우·2023년 12월 4일

10분 테코톡 - 5기

목록 보기
13/16

React Hooks란?

  • 2018년 React Conf에서 처음 소개되어 React v16.8에 도입된 기술
  • 함수형 컴포넌트에서 state 관리와 Life cycle을 다룰 수 있게 해주는 기술
    • useState()
    • useEffect()
    • useMemo()
    • useContext()
    • useCallback()
    • useRef()
    • ...

Hooks의 등장 배경

  • 기존의 리액트는 클래스형 컴포넌트를 기반으로 작업했다.
  • 클래스형 컴포넌트는 몇 가지의 불편함이 존재했습니다.

this

  • this는 클래스 자신을 가리킴
  • this가 가리키는 값은 변경 될 수 있다.
  • 변경될 수 있기 때문에 문제가 발생한다.
export default class ProfileFollowButton extends React.Component {
	handleClick = () => {
    	setTimeout(() => {
        	alert(`${this.props.user}를 팔로우했습니다.`)
        },3000)
    }
    
    return(){
    	return <button onClick={this.handleClick}>팔로우</button>
    }
}
  • 팔로우 버튼은 props로 유저 정보를 받고 클릭하면 3초 후 팔로우하는 기능을 가지고 있습니다.
  • 여기서 팔로우하는 3초 동안 유저가 바뀐다면 어떻게 될까요?
  • 이전 유저가 아니라 바뀐 유저가 팔로우되는 문제가 발생합니다.
  • 이는 컴포넌트가 리렌더링되면서 this가 가르키는 값이 변경되었기 때문
  • 고정되지 않은 this로 인해 발생한 버그 => this 사용이 어렵다

재사용성

  • 클래스 컴포넌트에서 상태 로직을 재사용 하기는 쉽지 않다.
  • HOC 패턴과 같은 방법으로 해결
  • 하지만 HOC에는 또 따른 문제가 발생함

그 외

  • 떨어지는 가독성, 낮은 성능 등..

함수형 컴포넌트의 사용 니즈 증폭

  • 앞서 말했던 다양한 문제들로 인해 개발자들은 함수형 컴포넌트를 사용하고 싶어했습니다.
  • 당시에도 함수형 컴포넌트는 존재했지만 상태 관리, 생명 주기, 렌더링 기능 등 다양한 기능을 제공하는 클래스형 컴포넌트와 달리 렌더링 기능이 주인 함수형 컴포넌트는 사용하기 어려웠습니다.

Hooks의 등장

  • 함수 컴포넌트에서도 상태 관리, 생명 주기 + 함수의 장점
  • Hooks의 등장으로 Class 컴포넌트에서 함수 컴포넌트로 대세가 이동했습니다.

Hooks의 이점

더 깔끔하고 간단한 코드

  • 초기값이 0인 count 상태 선언
  • 버튼을 누르면 count + 1

클래스형 컴포넌트

class Example extends React.Component {
	constructor(props){
    	super(props);
      	this.state = {
        	count: 0
        }
    };
  
  	handleClick(){
    	this.setState({ count: this.state.count + 1})
    }
  
  	render(){
    	return (
        	<div>
              <p>You clicked {this.state.count} times</p>
              <button onClick={this.handleClick.bind(this)}>Click Me</button>
            </div>
        )
    }
}

함수형 컴포넌트

const Example = () => {
	const [count, setCount] = useState(0);
  
  	const handleClick = () => {
    	setCount(count + 1);
    }
    
    return (
    	<div>
        	<p>You clicked {count} times</p>
        	<button onClick={handleClick}>Click Me</button>
        </div>
    )
}

React의 Life Cycle

  • 마운트, 업데이트, 언마운트 총 3가지 라이프사이클이 있다.
  • Mount
    • 처음 컴포넌트가 생성되고 렌더링을 거치는 과정
    • componentDidMount() => Class 컴포넌트
  • Update
    • props 혹은 state가 변경될 때, forceUpdate()가 실행되었을 때 리렌더링하는 과정
    • componentDidUpdate() => Class 컴포넌트
  • Unmount
    • 컴포넌트가 종료되는 과정
    • componentWillUnmount() => Class 컴포넌트

Hooks를 사용한 함수형 컴포넌트

  • Hooks가 등장한 이후 부터는 위의 3가지 함수를 useEffect 함수로 사용할 수 있습니다.
  • 컴포넌트가 마운트될 때 updateList함수를 실행
  • id props가 변경될 때 updateList함수를 실행
componentDidMount(){
	this.updateList(this.props.id);
}

componentDidUpdate(){
	if(prevProps.id === this.props.id) return;
  
  	this.updateList(this.props.id)
}
  • useEffect를 사용한다면? (의존성 배열 추가)
useEffect(() => {
	updateList(id);
},[id])
  • 컴포넌트가 Mount 될 때 스크롤 방지 스타일 추가
  • 컴포넌트가 Unmout될 때 스크롤 방지 스타일 제거
componentDidMount(){
	document.body.style.overflow = "hidden";
}

componentWillUnmout(){
	document.body.style.removeProperty('overflow')
}
  • useEffect를 사용한다면? (클린업 함수 사용)
useEffect(() => {
	document.body.style.overflow = "hidden";
  
  	return () => document.body.style.removeProperty('overflow');
}, [])

재사용성

  • 클래스 컴포넌트에서 상태 로직을 재사용하기는 어렵다.
  • HOC 패턴을 활용해 로직을 재사용할 수 있다.

HOC (Higher Order Component)란? [고차 컴포넌트]

  • 화면에서 재사용 가능한 로직을 분리해서 컴포넌트를 만들고, 재사용 불가능한 부분은 parameter로 받아서 처리하는 방법

사용자 나이 정보 페이지

class UserAgePage extends React.Component {
	state = {
    	users: []
    };

	componentDidMount(){
    	fetchUsers().then((users) => {
        	this.setState({ users });
        })
    }

	render(){
    	<div>
        	<p>사용자의 나이 페이지</p>
        	{users.map({ name, job }) => (
        		<div key={name}>
            		<p>
                      {name}: {job}  
                    </p>
            	</div>
        	)}
        </div>
    }
}

사용자의 직업 정보 페이지

class UserJobPage extends React.Component {
	state = {
    	users: []
    };

	componentDidMount(){
    	fetchUsers().then((users) => {
        	this.setState({ users });
        })
    }

	render(){
    	<div>
        	<p>사용자의 직업 페이지</p>
        	{users.map({ name, job }) => (
        		<div key={name}>
            		<p>
                      {name}: {job}  
                    </p>
            	</div>
        	)}
        </div>
    }
}
  • 2개의 컴포넌트는 렌더링하는 부분만 살짝 다르고 데이터를 패칭하는 부분은 동일합니다.
  • 클래스형 컴포넌트에서는 이러한 부분을 어떻게 재사용할까요?

고차 컴포넌트 만들기

function usersHOC(Component){
	return class usersHOC extends React.Component {
      state = {
          users: []
      };

      componentDidMount(){
          fetchUsers().then((users) => {
              this.setState({ users });
          })
      }
  
  	  render(){
      	return <Component {...this.props}  {...this.state} />;
      }
    }
}
  • 중복된 부분을 고차 컴포넌트로 만들고 인자로 Component를 받습니다.
  • 인자로 받은 Component를 render()에 넣어서 컴포넌트의 props로 유저 state를 전달합니다.
function UserAgePage({ users }){
	// ...
}

export default usersHOC(UserAgePage)

function UserJobPage({ users }){
	// ...
}

export default usersHOC(UserJobPage)
  • 각 페이지 컴포넌트는 usersHOC를 감싸서 사용한다.

Wrapper 지옥

  • Hook이 도입되기 전, HOC 패턴은 추천되는 패턴이었습니다.
  • 하지만 HOC 패턴에는 Wrapper 지옥이라는 큰 문제가 하나 있었습니다. => Callback 지옥이 생각이 나네요?
<ThemeHOC>
  <UserHOC>
    <AuthHOC>
      <MyComponent />
    </AuthHOC>  
  </UserHOC>
</ThemeHOC>

함수형 컴포넌트의 Custom Hook

const useFetchUser = () => {
	const [users, setUsers] = useState([]);
  	
  	useEffect(() => {
    	fetchUsers().then(users => {
        	setUsers(users);
        })
    },[])
  
  	return users;
}
  • 유저 fetching 로직을 수행하는 커스텀 훅

정리

React Hooks란?

  • 함수형 컴포넌트에서 state 관리와 Life Cycle을 다룰 수 있게 해주는 기술

Hooks의 도입 이유?

  • 클래스형 컴포넌트에서 발생하는 몇 가지 문제들을 해결하기 위해

Hooks의 이점?

  • 훨씬 깔끔하고 간단한 코드를 작성할 수 있다.
  • 재사용성을 높일 수 있다.

마무리

이번 글에서는 React Hooks에 대해서 다뤘는데요. 영상을 보기전에는 React Hooks에 대한 사용법이나 꿀팁 같은 영상일줄 알았는데 직접 보니까 그게 아니라 React Hooks가 나온 배경과 나옴으로써 얻은 이점에 대해서 설명하는 영상이네요. React를 처음 배울 때부터 함수형 컴포넌트로만 배워서 클래스형 컴포넌트는 ErrorBoundary 밖에 사용을 안해봤는데 이번에 모르던 개념들을 또 배우고갑니다!

Reference

profile
흑우 모르는 흑우 없제~

0개의 댓글