[Unit 3] React Hooks

JeongYeon·2023년 5월 19일
0

[SEB FE]section4

목록 보기
6/16
post-thumbnail

Component & Hook

Function Component & Class Componennt

  • Class Component
 class Counter extends Component {
    constructor(props) {
        super(props);
        this.state = {
            counter: 0
        }
        this.handleIncrease = this.handleIncrease.bind(this);
    }
    handleIncrease = () => {
        this.setState({
            counter: this.state.counter + 1
        })
    }
    render(){
       return (
            <div>
                <p>You clicked {this.state.counter} times</p>
                <button onClick={this.handleIncrease}>
                    Click me
                </button>
            </div>
       ) 
    }
}

클래스 컴포넌트는 복잡해질수록 이해하기 어렵고, 컴포넌트 사이에서 재사용하기 어렵다는 단점이 있다.
클래스 컴포넌트를 사용하기 위해서는 this키워드의 동작을 알아야하는데 문법을 정확히 알지 못하면 사용하기 어려웠다.

  • Function Component
function Counter () {
    const [counter, setCounter] = useState(0);
    const handleIncrease = () => {
        setCounter(counter + 1)
    }
    return (
        <div>
            <p>You clicked {counter} times</p>
            <button onClick={handleIncrease}>
                Click me
            </button>
        </div>
    )
}

함수형 컴포넌트는 클래스 컴포넌트보다 훨씬 직관적이고 보기 쉽다는 특징이 있다.


Hook
Hook은 React 16.8에 새로 추가된 기능입니다. Hook은 class를 작성하지 않고도 state와 다른 React의 기능들을 사용할 수 있게 해 줍니다
Hook은 함수형 컴포넌트에서 상태 값 및 다른 여러 기능을 사용하기 편리하게 해주는 메서드를 의미한다.
Hook은 function으로만 리액트를 사용할 수 있게 해주기때문에 클래스형 컴포넌트에서는 동작하지 않는다

...
render(){
    /* 클래스 컴포넌트는 render() 안에서 변수를 작성할 수 있습니다. */
    const [counter, setCounter] = useState(0);
...
}




HooK 사용 규칙
1. 리액트 함수의 최상위에서만 호출해야 한다.

2.오직 리액트 함수 내에서만 사용해야 한다.

useMemo

useMemo
특정 값을 재사용하고자 할때 사용하는 Hook

function Calculator({value}){
	const result = calculate(value);
	return <>
      <div>
					{result}
      </div>
  </>;
}

해당 컴포넌트는 렌더링 할때마다 이 함수를 계속해서 호출하고, 그때마다 시간이 몇 초 이상 소요가 된다. 몇 초의 지연은 렌더링에도 영향을 미치지만 사용자 경험에도 좋지 못하다.

/* useMemo를 사용하기 전에는 꼭 import해서 불러와야 합니다. */
import { useMemo } from "react";
function Calculator({value}){
	const result = useMemo(() => calculate(value), [value]);
	return <>
      <div>
					{result}
      </div>
  </>;
}

위의 컴포넌트의 경우에는 value의 값이 계속 바뀌는 것이 아니라면 이 값을 어딘가에 저장해 두고 다시 꺼내다 쓸 수만 있으면 함수를 호출할 필요가 없다.
useMemo를 사용해 이전 렌더링의 value값을 그대로 재활용할 수 있다.
💡Memoization
메모이제이션은 기존에 수행한 연산의 결과값을 메모리에 저장해 두고, 동일한 입력이 들어오면 재활용하는 프로그래밍 기법이다.

useMemo가 이 개념을 이용해 복잡한 연산의 중복을 피하고 리액트 앱의 성능을 최적화 시킨다.


useCallback

useCallback
useMemo와 마찬가지로 메모이제이션 기법을 이용한 Hook이다.
useMemo는 값의 재사용을 위해 사용하고 useCallback은 함수의 재사용을 위해 사용한다.

function Calculator({x, y}){
	const add = () => x + y;
	return <>
      <div>
					{add()}
      </div>
  </>;
}

해당 컴포넌트가 리렌더링 되더라도 함수가 의존하고있는 x,y가 바뀌지 않으면 함수도 메모리 어딘가에 저장해 두고 재사용할 수 있다.
이때 useCallback을 사용하면 그 함수가 의존하는 값들이 바뀌지 않는 한 기존 함수를 계속해서 반환한다.

/* useCallback를 사용하기 전에는 꼭 import해서 불러와야 합니다. */
import React, { useCallback } from "react";
function Calculator({x, y}){
	const add = useCallback(() => x + y, [x, y]);
	return <>
      <div>
					{add()}
      </div>
  </>;
}

하지만 단순히 컴포넌트 내에서 함수를 반복해서 생성하기 위해 useCallback을 사용하는 것은 손해인 경우도 있다.
자식 컴포넌트의 props로 함수를 전달해 줄때 useCallback을 사용하는 것이 좋다.


Custom Hooks

Custom Hooks
개발자가 스스로 커스텀한 훅을 말하며 이를 이용해 반복되는 로직을 함수로 뽑아내 재사용할 수 있다.
여러 url을 fetch할 때, 여러 input에 의한 상태 변경 등 반복되는 로직을 동일한 함수에 작동하게 하고싶을때 주로 사용한다.
커스텀 훅을 사용하면
1. 상태관리 로직의 재활용 가능
2. 클래스 컴포넌트보다 적은 야으이 코드로 동일한 로직 구현 가능
3. 함수형으로 작성하기 때문에 보다 명료함

//FriendStatus : 친구가 online인지 offline인지 return하는 컴포넌트
function FriendStatus(props) {
  const [isOnline, setIsOnline] = useState(null);
  useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    return () => {
     ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });
  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}
//FriendListItem : 친구가 online일 때 초록색으로 표시하는 컴포넌트
function FriendListItem(props) {
  const [isOnline, setIsOnline] = useState(null);
  useEffect(() => {
    function handleStatusChange(status) {
      setIsOnline(status.isOnline);
    }
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
    return () => {
     ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });
  return (
    <li style={{ color: isOnline ? 'green' : 'black' }}>
      {props.friend.name}
    </li>
  );
}

온라인인지 오프라인인지 확인하는 컴포넌트와, 온라인일때 초록색으로 표시하는 컴포넌트가 있다. 이 두 컴포넌트는 똑같이 쓰이는 로직이 존재한다.
이 로직을 빼내서 Custom hook을 사용할 수 있다.

function useFriendStatus(friendID) {
 const [isOnline, setIsOnline] = useState(null);
 useEffect(() => {
   function handleStatusChange(status) {
     setIsOnline(status.isOnline);
   }
   ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
   return () => {
     ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
   };
 });
 return isOnline;
}

두 컴포넌트의 동일한 로직을 분리해서useFriendStatus라는 함수로 만들 수 있다.


이때, Custom Hook을 정의하는 규칙이 있다.

  • 함수 이름 앞에 use를 붙인다.
  • 프로젝트 내의 hooks 디렉토리에 Custom Hook을 위치시킨다.
  • 조건부함수가 아니어야 한다.
    return하는 값이 조건부이면 안된다.


function FriendStatus(props) {
  const isOnline = useFriendStatus(props.friend.id);
  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}
function FriendListItem(props) {
  const isOnline = useFriendStatus(props.friend.id);
  return (
    <li style={{ color: isOnline ? 'green' : 'black' }}>
      {props.friend.name}
    </li>
  );
}

위에서 만든 useFreindStatus 훅을 컴포넌트에 적용했다.
로직을 분리해서 만들었기 때문에 더 직관적으로 확인이 가능하다.

하지만 같은 Custom hook을 사용했다고 해서 두 개의 컴포넌트가 같은 state를 공유하는 것은 아니다.
로직만 공유하고 state는 컴포넌트 내에서 독립적으로 정의되어 있다.


내용 참조, 출처 : 코드스테이츠
이미지 출처 : 코드스테이츠

profile
프론트엔드 개발자 될거야( ⸝⸝•ᴗ•⸝⸝ )੭⁾⁾

0개의 댓글

관련 채용 정보