[React-TIL] 리액트 라이프사이클(life-cycle)

Leesu·2023년 2월 21일
0
post-thumbnail

오늘은 useEffect 를 공부하며 배웠던 리액트 라이프사이클에 대해 정리한다.


❗리액트의 생명주기

리액트 클래스 컴포넌트는 라이프 사이클 메서드를 사용하고, 함수형 컴포넌트는 Hook을 사용한다.

여기서 '컴포넌트'는 생성(mounting) -> 업데이트(updating) -> 제거(unmounting)의 생명주기를 갖는다.


1. 클래스 컴포넌트

💥 1) 마운트(mounting) : 컴포넌트가 생성되는 시점에 발생💥

🟡 constructor

  • 컴포넌트가 생성되면 가장 먼저 실행되는 생성자 메서드이다.
  • this.props,this.state 에 접근하여 리액트 요소를 반환한다.

🟡 getDerivedStateFromProps

  • props 로부터 받아온 것을 state에 넣을 때 사용한다.

🟡 render

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

🟡 componentDidMount

  • 컴포넌트의 첫번째 렌더링이 끝나면 호출되는 메서드이다.
    따라 이 메서드가 호출된 시점에는 이미 렌더링, 즉 화면에 컴포넌트가 나타난 상태이다.
  • 주로 DOM 을 사용해야하는 외부 라이브러리 연동, 필요한 데이터를 fetch, ajax 로 요청하는 행위가 이루어진다.

💥2) 업데이트(updating) : 컴포넌트가 업데이트 되는 시점💥

🟡 getDerivedStateFromProps

  • 컴포넌트의 propsstate가 바뀌었을 때 호출되는 메서드이다.

🟡 shouldComponentUpdate

  • 컴포넌트의 리렌더링 여부를 결정하는 메서드이다.
  • React.memo 와 유사하며, boolean 으로 반환이 결정된다.

🟡 componentDidUpdate

  • 컴포넌트의 업데이트가 끝난 뒤 실행되는 메서드이다.
  • useEffect 의 의존성 매개변수가 변할때만 실행되는 것과 같다. 바뀐 값이 있어야만 실행되는 메서드

💥3) 언마운트(unmount) : 컴포넌트가 화면에서 사라지는(제거되기 직전) 시점💥

🟡 componentWillUnmount

  • 컴포넌트가 화면에서 사라지기 직전에 호출되는 메서드이다.
  • DOM 에 등록되어있던 이벤트가 제거된다. 예를들어 setTimeout 이 있다면 clearTimeout 을 통해 제거된다.
  • 외부 라이브러리를 사용하였을 경우, 라이브러리의 discopse 기능이 있다면 이때 호출시키면 된다.

2. 함수형 컴포넌트

※ React-Hook 이란? - 공식문서는 여기!

Hook은 React 16.8에 새로 추가된 기능입니다. Hook은 class를 작성하지 않고도 state와 다른 React의 기능들을 사용할 수 있게 해줍니다.

즉, Hook 은 함수형 컴포넌트가 클래스 컴포넌트의 기능을 사용할 수 있도록 해주는 기능이다.

※ 도입된 계기에 대한 - 공식문서는 여기!

💥1) 사용 규칙💥

  • 최상위(at the top level)에서만 Hook을 호출해야 합니다. 반복문, 조건문, 중첩된 함수 내에서 Hook을 실행하지 마세요.

  • React 함수 컴포넌트 내에서만 Hook을 호출해야 합니다. 일반 JavaScript 함수에서는 Hook을 호출해서는 안 됩니다.

  • 추가로, Eslint 를 사용하면 위 2가지 규칙을 강제시킬 수 있다.

💥2) Hook 의 종류와 개념 💥

🟡 useState

const [ state, setState ] = useState(초기값);
  • 위에서 state는 변수, setStatestate 를 변경시켜주는 함수이다.
  • 즉, useStatestate,setStatereturn 하면서 초기값을 설정해주는 hook 이다.

🟡 useEffect

useEffect(() => {}); 
// 렌더링 결과가 실제 돔에 반영된 후마다 호출, 모든 경우에 호출되며 실행된다.

useEffect(() => {}, []); 
// 컴포넌트가 처음으로 마운트 되었을 때 실행된다. 그 이후에는 실행되지 않는다.

useEffect(() => {}, [의존성1, dependency2, ..]); 
// 조건부 effect 발생, 의존성 중 하나가 변경된다면 effect는 항상 재생성된다.
// 만약 dependency 에 들어있던 값이 3번 번경된다면 useEffect 함수는 3번 실행된다.
  • useEffect 함수가 포함된 컴포넌트가 처음 마운트되거나 컴포넌트가 리렌더링 될 때,
    선언된 변수의 값이 변경되거나 redux, recoil 등 상태의 값이 변경될 때 실행할 구문들을 정의해놓은 함수이다.

  • +) useEffect 에는 컴포넌트가 언마운트될 때 실행되는 cleanup 함수라는 기능이 있다!

    • 컴포넌트가 사라질 때 호출되는 부분으로 메모리 누수를 방지하여 메모리를 관리하거나,
      컴포넌트가 사라질 때 수행할 작업들을 추가하기 위해 사용한다.
    • 또, 컴포넌트가 여러 번 렌더링 된다면 다음 effect가 수행되기 전에 이전 effect가 정리된다.
    useEffect(() => {
      ... // 실행할 내용
    
      return () => {
        ... // cleanup
      }
    });
    • +) 만약, 화면을 다 그리기 이전에 동기화되어야 하는 경우에는 useLayoutEffect 를 활용하면 된다.
    • 컴포넌트 렌더링 - useLayoutEffect 실행 - 화면 업데이트 순으로 effect 를 실행시킬 수 있다.
    • 둘의 차이점이 궁금하다면 여기를 참고!

🟡 useContext

  • context 객체(React.createContext에서 반환된 값)을 받아 그 context의 현재 값을 반환한다.
  • context를 이용하면 단계마다 일일이 props를 넘겨주지 않고도 컴포넌트 트리 전체에 데이터를 제공할 수 있다.
// - App.js

import React, { createContext } from "react";
import Children from "./Children";

// Context 객체를 생성한다.
export const AppContext = createContext();

const App = () => {
  const user = {
    name: "홍길동",
    age: 25,
  };

  return (
    <>
      // AppContext 로 Children 컴포넌트를 감싸면 AppContext 하위의 컴포넌트에서
      // value 를 사용할 수 있게 된다. 
      <AppContext.Provider value={user}>
        <div>
          <Children />
        </div>
      </AppContext.Provider>
    </>
  );
};

export default App;
// - Children.js

import React from "react";
import { AppContext } from "./App";

const Children = () => {
  return (
      <AppContext.Consumer>
        {(user) => (
          <>
            <h3>user의 이름은 {user.name}입니다.</h3>
            <h3>user의 나이는 {user.age}입니다.</h3>
          </>
        )}
      </AppContext.Consumer>
  );
};

export default Children;
  • createContext : Context 객체를 만든다.
  • Provider : 생성된 Context 의 props 를 하위 컴포넌트에 전달하는 역활을 한다.
  • Consumer : Context 의 변화를 감시하는 역활을 한다.

🟡 useReducer

const [state, dispatch] = useReducer(reducer, initialArg, init);
  • useState의 대체 함수로 컴포넌트 상태 업데이트 로직을 컴포넌트에서 분리시킬 수 있다.
  • (state, action) => newState의 형태로 reducer를 받고 dispatch 메서드와 짝의 형태로 현재 state를 반환합니다.
  • 즉, reducer란 현재 상태와 액션 객체를 파라미터로 받아와서 새로운 상태를 반환해주는 함수이다.

🟡 useCallback

const memoizedCallback = useCallback(
  () => {
    doSomething(a, b);
  },
  [a, b],
);
  • 메모이제이션된 값을 반환한다. => 이미 연산 된 값을 리렌더링 시 다시 계산하지 않도록 한다.
  • 의존성이 변경되었을 때에만 메모이제이션된 값만 다시 계산한다. 의존성 배열이 없는 경우 매 렌더링 때마다 새 값을 계산한다.
  • useCallback(fn, deps)useMemo(() => fn, deps) 와 같다.
  •   +) 추가로, Memoization이란 한번 연산해본 결과를 기억하고, 다시 동일한 입력이 들어오면 기억해둔 데이터를 반환하는 방법이다.

🟡 useMemo

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
  • 메모이제이션된 값을 반환하며, 렌더링 중에 실행된다.
  • 의존성이 변경되었을 때에만 메모이제이션된 값만 다시 계산한다. 의존성 배열이 없는 경우 매 렌더링 때마다 새 값을 계산한다.
  • 첫번째 파라미터에는 어떤 연산을 할지 함수를 정의하고,
    두번째 파라미터에는 useEffect와 마찬가지로 deps배열을 넣어주면 되는데
    이는 이 배열 안에 넣은 내용이 변경되면 우리가 등록한 함수를 호출해서 값을 연산해준다.
  • useMemo 의 첫번째 인자는 결과값을 생성해주는 팩토리 함수이고, 두번째 인자는 기존 결과값 재활용 여부의 기준이되는 입력값 배열입니다.

🟡 useRef

const refContainer = useRef(initialValue);
  • useRef.current 프로퍼티로 전달된 인자(initialValue)로 초기화된 변경 가능한 ref 객체를 반환한다. 반환된 객체는 컴포넌트의 전 생애주기를 통해 유지된다.
  • 즉, useRef 란 어떠한 특정 DOM을 선택할 수 있게 해준다.
  • JavaScript 의 querySelector 와 비슷하게 사용된다.
  • 아래는 예시이다.
function TextInputWithFocusButton() {
  const inputEl = useRef(null);
  const onButtonClick = () => {
    // `current` points to the mounted text input element
    inputEl.current.focus();
  };
  return (
    <>
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>Focus the input</button>
    </>
  );
}
profile
기억력 안 좋은 FE 개발자의 메모장

0개의 댓글