React Hook.. ✨

이유한·2023년 9월 28일
1

Front-End

목록 보기
3/4
post-thumbnail

React!

리액트에는 두 가지 형태의 컴포넌트가 있다.!

Class, Functional Component!

요즘엔 함수형 컴포넌트를 많이 쓴다지만 라이프 사이클의 이해를 위해선 클래스형 컴포넌트의 이해도 필요할 거 같다!
클래스형과 함수형의 가장 큰 차이는 여러 가지가 있지만 아무래도 라이프 사이클 메서드의 사용에 있어서가 가장 클 것 같다!

잠시 빌려용

클래스형 컴포넌트에서의 리액트 라이프 사이클입니당

잠깐 보는 클래스형 컴포넌트에서의 라이프 사이클 메서드

1. Mount - 컴포넌트가 생성되는 시기

constructor
컴포넌트의 생성자 메서드, 컴포넌트가 생성됐을 때 가장 먼저 실행이 되고 props, state 등에 this 키워드를 이용해 접근할 수 있고 리액트 요소를 반환한다.!

getDerivedStateFromProps
props로부터 파생된 state를 가져온다!! props로 받아온 데이터를 state에 넣어줄 떄 사용된다!!

render
컴포넌트를 렌더링 하는 메서드

componentDidMount
컴포넌트가 마운트 됐을 때 호출된다!! (컴포넌트의 첫 렌더링을 마치게 되면 호출되는 메서드)
이 메서드가 호출됐을 때는 화면에 컴포넌트가 그려진 상태이다.
주로 DOM을 다루는 외부 라이브러리 연동이나 해당 컴포넌트에서 사용될 데이터를 요청하는 등의 로직이 구현된다.!

2. Update - 컴포넌트가 업데이트 되는 시기

getDerivedStateFromProps
컴포넌트의 props, state가 변경됐을때도 이 친구가 호출된다!

shouldComponentUpdate
컴포넌트가 리렌더링을 할지 말지를 결정하는 메서드이다!

componentDidUpdate
컴포넌트가 업데이트 되고 난 후 호출된다!

3. Unmount - 컴포넌트가 화면에서 사라지는 것

componentWillUnmount
컴포넌트가 화면에서 사라지기 직전에 호출된다!
주로 DOM에 등록했던 이벤트리스너나 더이상 필요없는 구독 등을 제거하고 만약 setTimeout과 같은 함수를 등록했었다면 제거하는 로직을 구현한다!

메서드를 사용해 라이프 사이클에서의 로직을 관리할 수 있지만 함수형 컴포넌트는 이러한 메서드가 없습니다..!!

그렇다면 어떻게 컴포넌트의 생성(Mount) 업데이트(Update) 제거(UnMount)에서의 상태를 관리하지??

네! Hook을 사용합니다.!

  • 리액트에서 Hook은 함수형 컴포넌트에서도 상태와 라이프 사이클에 접근할 수 있도록 해주는 함수이다!!

이를 이용한 장점으로는

  • 기존 라이프 사이클 메서드에서는 실제 컴포넌트의 라이프 사이클과 관련 없는 로직이 섞여 들어갈 수 있는데 이로인해 버그가 쉽게 발생하거나 상태의 무결성을 해칠 수 있다.
  • 그렇기에 함수형 컴포넌트에서 훅을 사용하게 된다면 기존의 메서드 기반이 아닌 필요 로직 기반으로 관리할 수 있기에 효율적인 상태 관리나 라이프 사이클 접근이 가능하고
  • 컴포넌트를 함수 단위로 잘게 쪼갤 수 있다는 장점이 있다!

어떻게 써?

  • 리액트의 함수 컴포넌트 내부에서만 호출해야한다!!
  • 함수 컴포넌트의 최상단,,! 최상위 스코프에서만 Hook을 호출해야한다!
    • 반복문이나 조건문, 내부 선언 함수 등 하위 스코프에서 Hook을 실행하면 안된다
    • 컴포넌트가 렌더링 될때마다 항상 동일한 순서로 Hook이 호출되는 것을 보장하기 위함!
  • Hook의 이름은 use로 시작해야한다!! 통일성을 위한 규칙?

이러한 Hook은 어떤 것이 있으려나?

  • useState
    컴포넌트의 상태 변수를 관리한다! state가 변하게 되면 컴포넌트는 변화된 상태를 감지해 리렌더링이 된다!!

    여기서 주의할 점!
    상태 변수에 Object를 넣게 된다면 오브젝트 내부의 값을 변화시켜도 리렌더가 되지 않는 경우가 있을 수 있다.
    그 이유로는 리액트의 불변성을 지키기 위해서!!
    자바스크립트 엔진의 메모리 구조에서는 원시 타입 변수와 참조 타입 변수의 참조 값은 콜 스택에 저장하고 참조 타입 변수의 실제 값은 메모리 힙에 저장하게 되는데 리액트에서는 상태 변화의 감지를 콜 스택에서 한다!!
    그렇기 때문에 배열에 push 등을 사용해 값에 변화를 주거나 구조분해할당을 하지 않은 채 객체의 값을 변화시키면 메모리 힙에 접근해 실제 값만 변경시켜 참조 값은 변화되지 않기에 상태의 변화를 감지하지 못해 리렌더링이 일어나지 않게 된다!
    그렇기에 참조 타입의 Object 상태를 변화시켜 리렌더를 요한다면 setState 시 구조 분해 할당 등을 통해 새 참조 값을 만들 수 있도록 해야한다!
    객체의 경우에는 쪼개서 상태로 만들 수 있다면 그렇게 하는 것이 추천된다

또한 setState는 비동기로 작동한다! => state의 값은 setState가 호출되는 시점이 아닌, 해당 로직이 구현된 스코프의 로직이 모두 실행된 이후에 바뀐다!!

whY??

setState가 여러 개 있을 수도 있고 변경될때마다 바로바로 렌더링이 되면 성능 상 유리하지 않기에!

const [name, setName] = useState(initialState);
  • useEffect
    화면에 렌더링이 완료된 후 수행!! componentDidMount, componentDidUpdate, componentWillMount가 합쳐졋다!
    useEffect 내부의 리턴문은 컴포넌트에서의 Unmount 시점을 위해 사용된다!
    • 메모리 누수 방지를 위해 화면에서 컴포넌트가 사라지기 전에 수행
    • 컴포넌트가 여러 번 렌더링 된다면 다음 effect가 수행되기 전에 이전 effect가 정리도니다!
// 렌더링 결과가 실제 DOM에 반영된 후마다 호출
useEffect(() => {});
// 의존성 배열을 비워두면 컴포넌트가 처음 나타날 떄 한 번 호출
useEffect(() => {}, []);
// 의존성 배열에 상태를 넣게 되면 조건부 effect 발생, 의존성이 변경되면 effect는 항상 재생성된다.
useEffect(() => {}, [dependency]);
  • useLayoutEffect
    useEffect의 친구! 기본적으로 useEffect는 Side Effect(부수 효과)를 막기 위해 화면 렌더링이 완료된 후나 상태가 업데이터 되었을 떄 사이드 이펙트를 수행한다!
    useEffect의 내용은 컴포넌트가 렌더된 후 layout과 paint가 왼료된 후에 비동기적으로 수행된다! 그렇기에 DOM에 영향을 주는 로직이 있을 경우 사용자는 화면이 재구성됨에 따라 깜빡임을 마주할 수 밖에 없다!
    useLayoutEffect는 컴포넌트가 렌더된 후 layout과 paint가 왼료되기 전에 동기적으로 수행되기때문에 DOM을 바꾸는 효과가 있더하더라도 이미 완료된 화면을 보기 때문에 UX 면에서 좋다!
    하지만 로직이 복잡하고 오래 걸린다면 화면이 그려지기까지의 시간이 길 수 밖에 없기 때문에 자주 사용되는 훅이지는 않다!

  • useContext
    전역 변수를 위한 훅!! Context API를 통해 만들어진 Context에서 제공하는 값을 가져올 수 있다!

const data = useContext(DataContext);

컴포넌트에서 가장 가까운 <DataContext.Provider>가 갱신된다면 이 훅은 프로바이더에게 제공된 가장 최신의 데이터를 사용해 렌더러를 트리거한다!

  • useReducer
    useState의 대체 훅으로 컴포넌트 상태 업데이트 로직을 컴포넌트에서 분리시킬 수 있다!
    컴포넌트 바깥에 작성할수도 있고 심지어 모듈처럼 다른 파일에 작성해 불러와서 사용할수도 있따!
    reducer란 현재 state와 action 객체를 파라미터로 받아 새로운 state를 반환하는 함수다!
const [state, dispatch] = useReducer(reducer, initialArgument, init);
  • useRef
    특정 DOM 객체를 선택할 때 주로 사용되며 current 프로퍼티로 변경 가능한 DOM 객체의 ref 객체를 반환한다!
    반환된 객체는 컴포넌트의 전 라이프 사이클을 통해 유지된다!
const ref = useRef(null);
  • useMemo
    메모이제이션 된 값을 반환한다! 어떠한 값을 연산 등을 통해 얻는 로직이 있다할 떄 매 리렌더마다 다시 연산하지 않도록 연산된 값을 저장해준다!
    의존성이 변경됐을 때만 메모이제이션 된 값을 다시 연산한다!
    의존성이 없는 경우엔 매 렌더링마다 새 값을 연산한다!
const memo = useMemo(() => doingSomething(a, b), [a, b]);
  • useCallback
    useMemo와 유사한 훅! 메모이제이션 된 콜백을 반환한다!
    의존성이 변경되었을 때만 변경되어 특정 함수를 새로 생성하지 않고 재사용 가능하도록 한다!
    useMemo, useCallback 두 훅 모두 메모이제이션을 사용해 중복 연산을 줄이고 참조된 값이 변경됐을 때만 등록된 함수를 실행한다는 공통점이 있지만 반환 값에서 차이가 있다!
    useCallback은 주로 하위 컴포넌트에 props로 함수를 전달할 경우나 외부에서 데이터를 받아올 때 사용된다!
    함수는 값이 아닌 참조 주소로 비교되기 때문에 함수의 참조 값을 동일하게 유지시키며 메모이제이션이 필요할 떄 주로 사용된다!
const memoCallback = useCallback(() => {
	doingSomething(a, b);
}, [a, b]);
profile
후론트 개발자 👩🏻‍💻

1개의 댓글

comment-user-thumbnail
2023년 9월 28일

완전 천재!!! 그 자체 🥰

답글 달기