Hook & Context

김지윤·2022년 6월 29일
0

React

목록 보기
3/6

reactjs hook 공식내용 : https://reactjs.org/docs/hooks-intro.html

Basic Hook

1. useState : 컴포넌트의 각 state값을 제어 하는 Hook

ex) Example2 컴포넌트 -> state에 객체가아닌 변수값을 사용했을 경우

import {useState} from "react";

const Example2 = (props) => {
    const [count, setCount] = useState(0);

    const handleClick = (e) => {
        setCount(count + 1);
    };

    return (
      <div>
          <p>You Clicked {count} Iimes</p>
          <button onClick={handleClick}>Click me</button>
      </div>
    );
}

export default Example2;

ex) Example3 컴포넌트 -> state를 셋팅 시 객체를 리턴하는 형태로 사용했을 경우

import {useState} from "react";

// useState => count
// useState => { count: 0 }
const Example3 = (props) => {
    const [state, setState] = useState({ count : 0 });

    const handleClick = (e) => {
        setState((state) => ({count: state.count + 1 }));
    };

    return (
        <div>
            <p>You Clicked {state.count} Times</p>
            <button onClick={handleClick}>Click me</button>
        </div>
    );
}

export default Example3;
  1. Class로 작성할 경우 (state 셋팅)
    Functional Component = Stateless Component = Stateless Functional Component

  2. Hook의 작성의 경우 (state 셋팅)
    Functional Component != Stateless Component

Class와 Hook의 차이점

  • 컴포넌트 사이에서 상태와 관련된 로직을 재사용하기 어렵습니다.
    (컨테이너 방식 말고, 상태와 관련된 로직)
  • 복잡한 컴포넌트들은 이해하기 어렵습니다.
  • Class 는 사람과 기계를 혼동시킵니다.
    (컴파일 단계에서 코드를 최적화하기 어렵게 만든다.)
  • this.state는 로직에서 레퍼런스를 공유하기 때문에 문제가 발생할 수 있다.

2. useEffect : 라이프 사이클 훅을 대체 할 수 있다. (동등한 역할을 한다고 볼 수 없다.)

대체능한 라이프사이클 HOOK :

  • componentDidMount
  • componentDidUpdate
  • componentWillUnmount

useEffect( function, deps ) 사용법 

  • function : 수행하고자 하는 작업
  • deps : 배열 형태이며, 배열 안에는 검사하고자 하는 특정 값 or 빈 배열
  1. deps 에 특정 값을 넣게 된다면 컴포넌트가 처음 마운트 될 때, 지정한 값이 바뀔 때, 언마운트 될 때, 값이 바뀌기 직전에 모두 호출이 된다.

  2. useEffect 안에서 사용하는 상태나, props 가 있다면, useEffect 의 deps 에 넣어주어야 하는 것이 규칙이다.

  3. 만약 사용하는 값을 넣어주지 않는다면, useEffect 안의 함수가 실행될 때 최신 상태, props를 가리키지 않는다.

  4. deps 파라미터를 생략한다면, 컴포넌트가 리렌더링 될 때마다 useEffect 함수가 호출된다.

React를 만든 사람에 대한 내용 번역 : https://www.rinae.dev/posts/a-complete-guide-to-useeffect-ko

ex) Example4.jsx

import {useEffect, useState} from "react";

const Example4 = (props) => {
    const [count, setCount] = useState(0);

    const handleClick = (e) => {
        setCount(count + 1);
    };
    // mounted / update 시점 모두 커버
    // 순차 실행
    useEffect(() => {
        console.log("componentDidMount");
    }, []);

    // componentDidUpdate
    useEffect(() => {
        console.log("componentDidMount, componentDidUpdate by count", count);

        return () => {
            // clean up 클린업 하고 출력
            console.log("cleanup by count", count);
        }
    }, [count]);

    // componentWillUnmount
    useEffect(() => {
        console.log("componentWillUnmount");
        return () => {
          // clean up
        };
    }, []);

    return (
        <div>
            <p>You Clicked {count} Times</p>
            <button onClick={handleClick}>Click me</button>
        </div>
    );
}

export default Example4;

Custom Hooks

1. UseSomething

  • Browser에 resize 이벤트를 Hook으로 생성
    함수형 컴포넌트자체를 Hook의 형태로 생성 후 나만의 Hook을 생성할 수 있음

ex) UseWindowWidth.jsx

import {useEffect, useState} from "react";

const UseWindowWidth = (props) => {
    // State를 활용한 Custom Hook 생성
    const [width, setWidth] = useState(window.innerWidth);

    useEffect(() => {
        const handleResizeEv = () => {
            setWidth(window.innerWidth);
        }
        window.addEventListener("resize", handleResizeEv);

        return () => {
            window.removeEventListener("resize", handleResizeEv);
        }
    }, [])

    return width;
}

export default UseWindowWidth;
  • HOC와 HooK의 비교
    • HOC : withHasMounted.jsx
      • HOC의 경우 기존 컴포넌트를 넘길경우 그대로 Props를 전달함
      • 이후 컴포넌트 이름에 대한 변경을 해야함
// HOC
import {useEffect, useState} from "react";

const withHasMounted = (Component) => {
    const NewComponent = () => {
        const [hasMounted, setHasMounted] = useState(false);

        useEffect(() => {
            setHasMounted(true);
        }, [])

        return (
            <Component { ...Component.props} hasMounted={hasMounted}/>
        );
    };

    NewComponent.displayName = `withHasMounted(${Component.name})`;

    return NewComponent;
};

export default withHasMounted;
  • Hook : useHasMounted.jsx
    • Custom Hook으로 생성해서 쓰는 부분이 더 편하게 사용할 수 있다
    • 현재 추세로는 HOC보다 Custom Hook을 생성해서 쓰는 부분이 더 많음
//custom hook
import {useEffect, useState} from "react";

const useHasMounted = (props) => {
    const [hasMounted, setHasMounted] = useState(false);

    useEffect(() => {
        setHasMounted(true);
    }, [])

    return hasMounted;
}
export default useHasMounted;

App.js : HOC 및 CutomHook 로드

import useWindowWidth from "./hooks/UseWindowWidth";
import withHasMounted from "./hooks/withHasMounted";
import useHasMounted from "./hooks/useHasMounted";

function App({hasMounted}) {
  const width = useWindowWidth();
  const hasMountedFromHooks = useHasMounted();

  console.log(hasMounted, hasMountedFromHooks);
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <div>
          {width}
        </div>
      </header>
    </div>
  );
}

export default withHasMounted(App);
profile
윤의 개발자 블로그

0개의 댓글