[React] 10 - Hooks : useEffect (1)

jungeundelilahLEE·2021년 2월 19일
0

React

목록 보기
15/24

goal

  • react hook에 대해서 알아보자

Effect Hook

Side effect (= effects)

  • react component 내에서 데이터를 가져오거나 (예를 들면, fetch를 사용해서 api 정보를 가져오는 등) DOM을 직접 조작하는 (예를 들면, onClick 등을 활용) 동작을 뜻한다.
    이름의 어원 : 다른 component에 영향을 줄 수 있으며, 렌더링하는 과정에서는 구현할 수 없는 동작이기 때문

  • 컴퓨터공학에서는 함수의 로컬상태를 함수 외부에서 변경하는 경우, Side effect 가 발생했다고 얘기한다.
    따라서, 리액트에서 Side effect란?
    : 리액트의 함수형 컴포넌트의 밖에서 로컬의 상태를 변경하는 것을 뜻한다.


  • 그렇다면, 왜 리액트에서는 Side effect 의 개념이 필요한 것일까?
    • 대표적으로 "비동기처리"가 있다.
    • 리액트에서 컴포넌트를 rendering 할 때, 서버에서 값을 받아오는 경우를 생각해보자.
    • 컴포넌트의 lifecycle 중에서, 서버와 통신하게 되면, 화면이 잠시 멈추거나 끊기는 상황이 나타날 수 있다.
    • 따라서, 서버에서 값을 받아오는 작업은 lifecycle에 영향을 주지 않는 방법으로 처리해야 한다.
    • 이때, 컴포넌트의 lifecycle과 무관하게
    • 외부에서 비동기로 서버와 통신하고, 컴포넌트 state를 업데이트하는 Side effect 개념이 필요하게 된다.
    • 이러한 작업시, useEffect()가 매우 유용하게 사용될 수 있다.
    • 비동기처리, 병렬처리, setTimeout(), setInterval(), Event handling 등 시간이 많이 걸리거나, lifecycle과 무관한 작업을 수행하고 싶을 때 사용될 수 있다.
function UserInfo({ userId }) {
    const [user, setUser] = useState(null);
    //서버 통신은 컴포넌트 외부에서 실행(=Side Effect)
    // 1. useEffect()함수를 사용하여 외부에서 실행될 Side Effect 함수 등록
    // 2. Side Effect 함수 처리가 완료되면 컴포넌트 외부에서 컴포넌트 상태 업데이트
    useEffect(
        () => {
            getUserFromServer(userId)
                .then(userData => setUser(userData));
        },
        [userId]
    );
    return (
        <div>
            {!user && <p>조회 중입니다...</p>}
            {user && (
                <ul>
                    <li>{`아이디: ${user.name}`}</li>
                    <li>{`이메일: ${user.email}`}</li>
                </ul>
            )}
        </div>
    );
}
// 출처: https://nsinc.tistory.com/223 [NakedStrength]

  • useEffect는 function component 내에서 Side effects가 가능하게 한다.
    (= Side effect 함수를 처리할 때 사용한다.)
  • class component의 componentDidMount, componentDidUpdate, comonentWillUnmount 와 비슷한 역할을 한다. (하나의 api로 통합된 것)
  • effect를 해제하기 위해서는 해제하는 함수를 반환하면 된다. (optional)

  • 따라서, useEffect HOOK을 사용하면 (구독을 추가하고 제거하는 로직과 같이) 서로 관련 있는 코드들을 한군데에 모아서 작성할 수 있다. (class component에서 mount, update, unmount로 나눠서 넣은 것과 달리)

  • 단, 최상위(at the top level)에서만 HOOK을 호출해야 한다.
    • 이 규칙을 따르면 컴포넌트가 렌더링 될 때마다 항상 동일한 순서로 Hook이 호출되는 것이 보장된다.
    • useState와 useEffect가 여러번 호출되는 중에도 HOOK의 상태를 잘 유지할 수 있게 한다.

  • react function component 내에서만 HOOK을 호출해야 한다.
    • (예외) Custom Hook에서 Hook을 호출할 수 있다.


useEffect는 어떤 역할을 수행할까?

  • useEffect Hook을 이용하여 우리는 리액트에게 컴포넌트가 렌더링 이후에 어떤 일을 수행해야하는 지를 알려준다.
    • 컴포넌트 : to react "나 렌더링 했어~"
    • 리액트 : to component "기다려봐~ 아직 할게 더 남았어~ ㅋㅋ"
    • 컴포넌트 : to react "뭐 해야 되는데...?"
    • 리액트 : to component "일단, useEffect로 좀 가볼래? 거기 적혀 있어>_<"
  • 리액트는 우리가 넘긴 함수를 기억했다가(이 함수를 ‘effect’라고 부른다. / 여기서는 setCount) DOM 업데이트를 수행한 이후에 불러낼 것이다.
  • 위의 경우에는 effect를 통해 문서 타이틀을 지정하지만, 이 외에도 데이터를 가져오거나 다른 명령형(imperative) API를 불러내는 일도 할 수 있습니다.

useEffect를 컴포넌트 내부에서 불러내는 이유는?

  • useEffect를 컴포넌트 내부에 둠으로써 effect를 통해 state 변수에 (or 그 어떤 props에도) 접근할 수 있기 때문이다.

useEffect는 렌더링 이후에 매번 수행되는 걸까? : YES !

  • 기본적으로 첫번째 렌더링과 이후의 모든 업데이트에서 수행된다.
    effect를 렌더링 이후에 발생하는 것으로 생각하는 것을 추천
  • 리액트는 effect가 수행되는 시점에 이미 DOM이 업데이트되었음을 보장한다.


정리(Clean-up)를 이용하지 않는 ❌️ Effects

  • 클래스 컴포넌트
class EffectHookIM extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
          count: 0
        };
      }
    
      componentDidMount() {
        document.title = `You clicked ${this.state.count} times`;
      }
      componentDidUpdate() {
        document.title = `You clicked ${this.state.count} times`;
      }
    
      render() {
        return (
          <div>
            <p>You clicked {this.state.count} times</p>
            <button onClick={() => this.setState({ count: this.state.count + 1 })}>
              Click me
            </button>
          </div>
        );
      }
}
  • 함수 컴포넌트에서 HOOK 이용
function EffectHookIM () {
  const [count, setCount] = useState(0);

  useEffect(() => {
    document.title = `You clicked ${count} times`;
  });


  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}
  • state변수를 선언한 후, 리액트에게 effect를 사용함을 말하고 있다.
  • useEffect HOOK에 함수를 전달하고 있다.
    () => {document.title = `You clicked ${count} times`}
  • 이 함수가 바로 "effect" 이다!
    • effect 내부에서 document.title이라는 브라우저 API를 이용하여 문서 타이틀을 지정했다.
    • 같은 함수 내부에 있기 때문에 최신의 count를 바로 얻을 수 있었다.
  • 리액트는 컴포넌트를 렌더링할 때, 우리가 이용한 effect를 기억하였다가 DOM을 업데이트한 이후에 실행한다.
  • 이는 맨 첫번째 렌더링은 물론, 그 이후의 모든 렌더링에 똑같이 적용된다.
  • 여기 무슨 말인지 모르겠음....
  • useEffect에 전달된 함수가 모든 렌더링에서 다르다.
  • 의도된 것으로서, count 값이 제대로 업데이트 되는지에 대한 걱정 없이 effect 내부에서 그 값을 읽을 수 있게 하는 부분이다.
  • 리렌더링할 때마다 모두 이전과 다른 effect로 교체하여 전달한다.

출처 : https://nsinc.tistory.com/223 [NakedStrength]

profile
delilah's journey

0개의 댓글