[React] Hook

이한솔·2023년 11월 28일
0

React

목록 보기
1/2

React Hook

훅(Hook)은 리액트 v16.8에서부터 도입된 기능으로, 함수혀여 컴포넌트에서 상태 및 다른 리액트 기능을 사용할 수 있게 해준다.

훅(Hook) 사용 규칙

  1. 최상위에서만 Hook을 호출해야한다.
    • 반복문이나 조건문 혹은 중첩된 함수 내에서 Hook을 호출하면 안 된다.
  2. 컴포넌트 내에서만 Hook을 호출해야한다.
    • Hook은 리액트 함수 컴포넌트 내에서만 호출되어야한다. 일반 JavaScript 함수나 비동기 함수 내에서는 호출하지 않아야한다.
  3. Hook 호출 순서를 유지해야한다.
    • Hook은 동일한 순서로 호출되어야한다. 이는 컴포넌트 렌더링과 관련이 있다.

자주 사용하는 React Hook

1. useState

함수형 컴포넌트에서 상태를 추가하고 관리하기 위해서 사용한다. useState를 사용하면, 컴포넌트가 렌더링될 때 상태를 초기화하고, 이 상태를 갱신하여 컴포넌트를 업데이트할 수 있다.
const [state, setState] = useState(initialState);
  • state : 상태값 자체를 나타내는 변수
  • setState : 상태를 갱신할 때 사용되는 함수로, 새로운 상태 값을 받아와서 업데이트
  • initialState : 컴포넌트가 처음 렌더링될 때의 초기상태를 나타낸다.

useState의 특징

  1. 컴포넌트 상태관리
    : useState를 사용하여 컴포넌트 내에서 동적인 상태를 추가하고 관리할 수 있다. 상태가 변경되면 리액트는 해당 컴포넌트를 리렌더링한다.
import React, { useState } from 'react';

function ExampleComponent() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}
  1. 비동기적 업데이트
    : setState 함수를 사용하여, 상태를 갱신할 때, 리액트는 비동기적으로 업데이트를 수행하며, 연속적으로 호출되는 경우, 최적화를 위하여 여러 업데이트를 일괄적으로 처리한다.
function ExampleComponent() {
  const [count, setCount] = useState(0);

  const handleClick = () => {
    // 비동기적으로 업데이트
    setCount(count + 1);
    setCount(count + 1);
  };

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

이 예제에서 count는 2가 아닌 1이 된다.

  1. 이전 상태 활용
    : setState 함수는 이전 상태를 활용하여 업데이트할 수 있는 함수를 전달할 수 있다.
function ExampleComponent() {
  const [count, setCount] = useState(0);

  const handleIncrement = () => {
    // 이전 상태를 활용하여 업데이트
    setCount(prevCount => prevCount + 1);
  };

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={handleIncrement}>
        Increment
      </button>
    </div>
  );
}
  1. 여러 상태 사용
    : 컴포넌트에서 여러 개의 useState를 사용하여 여러 상태를 각각 독립적으로 관리할 수 있다.

    function MultiStateComponent() {
     const [count, setCount] = useState(0);
     const [text, setText] = useState('');
    
     return (
       <div>
         <p>Count: {count}</p>
         <p>Text: {text}</p>
         <button onClick={() => setCount(count + 1)}>
           Increment
         </button>
         <input
           type="text"
           value={text}
           onChange={(e) => setText(e.target.value)}
         />
       </div>
     );
    }

2. useEffect

리액트 함수형 컴포넌트에서 부수 효과를 수행하고, 컴포넌트 생명주기에 특정 작업을 처리하기 위해서 사용된다. useEffect는 컴포넌트의 렌더링 결과가 화면에 반영된 후에 비동기적으로 작업을 수행하거나, 컴포넌트가 마운트(mount)되었을 때, 언마운트(unmount)되었을 때 또는 특정 상태나 props가 변경되었을 때 실행하는 함수를 정의할 수 있다. ```JSX useEffect(() => { // 부수 효과 수행 또는 특정 상태/프롭스에 따라 실행될 코드 }, [/* 의존성 배열 */]); ```
  • 첫 번째 매개변수 : 부수 효과를 수행하는 함수를 정의
  • 두 번재 매개변수 (의존성 배열) : 언제 useEffect를 실행할지 결정한다. 배열에 포함된 값이 변경될 때만 useEffect가 실행된다. 만약 빈배열을 전달하면 컴포넌트가 마운트된 후 한 번만 실행된다.

useEffect의 특징

  1. 비동기 작업 수행
    : useEffect 안에서 비동기 작업을 수행할 수 있다. API 호출, 데이터 가져오기, 타이머 설정 등의 작업을 처리할 수 있다.
useEffect(() => {
  // 비동기 작업 수행
  const fetchData = async () => {
    const result = await fetchDataFromAPI();
    // 처리된 데이터를 사용하여 상태 갱신 등의 작업 수행
  };

  fetchData();
}, [/* 의존성 배열 */]);
  1. 클린업(clean-up) 함수 사용
    : useEffect는 부수 효과가 필요없을 때, 즉 언마운트(unmount)될 때 혹은 다음 useEffect 실행 전에 정리 작업을 수행할 수 있도록 반환된 함수를 활용할 수 있다.
useEffect(() => {
  // 컴포넌트가 마운트된 후 실행되는 코드

  return () => {
    // 언마운트 또는 다음 useEffect 실행 전에 실행되는 정리 함수
  };
}, [/* 의존성 배열 */]);
  1. 의존성 배열 활용
    : useEffect의 두번째 매개변수인 의존성 배열을 사용하여, 특정상태가 props가 변경될때만 useEffect가 실행되도록 설정할 수 있다.
    useEffect(() => {
     // 특정 상태가 변경될 때만 실행되는 코드
    }, [specificState]);

useEffect 사용 예시

  1. 컴포넌트가 마운트 되었을 때 및 언마운트 되었을 때
import React, { useEffect } from 'react';

function MountedComponent() {
  useEffect(() => {
    // 컴포넌트가 마운트된 후 실행되는 코드
    console.log('Component is mounted');

    // 정리 함수 (언마운트 또는 다음 useEffect 실행 전에 실행됨)
    return () => {
      console.log('Component will unmount or next useEffect will run');
    };
  }, []); // 빈 배열은 컴포넌트가 마운트될 때 한 번만 실행됨

  return <div>Mounted Component</div>;
}
  1. 특정 상태가 변경될 때
import React, { useEffect, useState } from 'react';

function StateChangeEffect() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    // count 상태가 변경될 때 실행되는 코드
    console.log('Count is updated:', count);
  }, [count]); // count가 변경될 때마다 실행됨

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>
        Increment Count
      </button>
    </div>
  );
}

3. useContext

컨텍스트(Context)를 활용하여 전역 상태를 공유하고자 할 때 사용한다. 컨텍스트는 컴포넌트 트리를 횡단하는 데이터를 전달할 수 있는 메커니즘을 제공하며, useContext는 이 컨텍스트에 접근하여 값을 가져오는데 사용된다.

Context 란?

일반적인 React 어플리케이션데서 데이터는 props를 통해서 부모 컴포넌트에서 자식 컴포넌트로 전달된다. 어플리케이션 안의 여러 컴포넌트들에게 props로 전달해줘야하는 경우, context를 이용하면 명시적으로 props를 넘겨주지 않아도 값을 공유할 수 있게 해준다. 즉, 데이터가 필요할 때마다 props를 통해 전달할 필요 없이 context를 이용해 공유한다.

  • createContext : 컨텍스트를 생성한다. 이 함수는 Provider와 Consumer를 생성하는데 사용된다.
  • const MyContext = createContext();
  • Provider : 컨텍스트 값을 제공하는 역할을 한다. Provicder로 감싼 컴포넌트 내에서 하위 컴포넌트들은 해당 컨텍스트 값을 사용할 수 있다.
  • ```JSX {/* 여기에 있는 컴포넌트들은 MyContext의 값을 사용할 수 있음 */} ```
  • Consumer : Provider로 감싼 컴포넌트 내에서 해당 컨텍스트 값을 소비하고자 할 때 사용된다. 최근 버전의 리액트에서는 useContext Hook을 사용하는 것이 일반적이다.

컨텍스트를 사용하면, 중첩된 컴포넌트 간에 데이터를 전달하는데에 용이하며, 특히 전역적인 상태나 테마, 사용자 인증 정보같은 데이터를 효율적으로 관리할 수 있다.

useContext 의 사용법

1. 컨텍스트 생성
먼저 'React.createContext'를 사용하여 컨텍스트를 생성한다.
// MyContext.js
import { createContext } from 'react';

const MyContext = createContext();

export default MyContext;
2. 컨텍스트 제공
컨텍스트의 값을 제공하려는 부모 컴포넌트에서 'Context.Provider'를 사용하여 값을 전달한다.
// ParentComponent.js
import React from 'react';
import MyContext from './MyContext';

function ParentComponent() {
  const contextValue = 'Hello from Context!';

  return (
    <MyContext.Provider value={contextValue}>
      {/* 자식 컴포넌트들 */}
    </MyContext.Provider>
  );
}

export default ParentComponent;
3. 컨텍스트 사용
자식 컴포넌트에서 useContext를 사용하여 컨텍스트 값을 가져온다.
// ChildComponent.js
import React, { useContext } from 'react';
import MyContext from './MyContext';

function ChildComponent() {
  const contextValue = useContext(MyContext);

  return (
    <div>
      <p>{contextValue}</p>
    </div>
  );
}

export default ChildComponent;

useContext 사용 시 주의 사항

  • useContext는 컨텍스트의 현재 값을 반환하며, 컨텍스트의 값이 변경될 때 컴포넌트를 리렌더링한다.
  • useContext를 사용하기 위해서는 해당 컨텍스트 Provider가 상위 계층에서 제공되어야한다.
  • 여러 개의 컨텍스트를 사용해야할 경우, 각각의 useContext를 사용하여 해당 컨텍스트의 값을 가져올 수 있다.

4. useRef

함수형 컴포넌트 내에서 참조(reference)를 관리하기 위해서 사용된다. useRef를 사용하면 DOM요소에 직접 접근하거나 컴포넌트 생명주기와 관련 없는 값을 유지할 수 있다.

useRef의 주요 특징

  • useRef로 생성한 객체는 current 속성을 통해 실제 값에 접근한다.
  • useRef로 생성한 참조는 컴포넌트가 리렌더링되어도 이전 값이 유지된다.
  • useRef로 생성한 참조는 변경되어도 컴포넌트가 리렌더링 되지 않는다. 따라서 값이 변경되어도 렌더링이 발생하지 않는다.

useRef는 주로 DOM조작, 애니메이션 및 다른 Hook들과의 조합 등에서 사용된다.

useRef의 사용법
1. DOM 요소에 접근

import React, { useRef, useEffect } from 'react';

function MyComponent() {
  // useRef를 사용하여 참조 생성
  const myInputRef = useRef(null);

  useEffect(() => {
    // 컴포넌트가 마운트되면 myInputRef.current가 해당 input 요소를 참조합니다.
    myInputRef.current.focus();
  }, []);

  return <input ref={myInputRef} />;
}
  1. 컴포넌트의 생명주기과 관련없는 값 관리
    렌더링 간에 값을 계속 유지하고 싶은 경우에 사용할 수 있다.
import React, { useRef, useState } from 'react';

function MyComponent() {
  const renderCount = useRef(0); // 렌더링 횟수를 기록하기 위한 useRef

  useEffect(() => {
    renderCount.current += 1;
    console.log(`Component has rendered ${renderCount.current} times.`);
  });

  return <div>Component content</div>;
}

5. useMemo / useCallback

두 Hook 모두 리액트에서 성능 최적화를 위해 사용되는 Hook이지만, 목적과 방법에서 차이가 있다.

useMemo

  • 목적 : 계산 비용이 많이 드는 함수의 결과 값을 캐싱하여 같은 계산이 반복되는 것을 방지하고 성능을 최적화 한다
  • 사용 예시 : 계산 비용이 높은 함수의 결과 값, 메모이제이션이 필요한 연산 등을 처리할 때 사용한다.
import React, { useMemo } from 'react';

function ExampleComponent({ list }) {
  const total = useMemo(() => {
    console.log('Calculating total...');
    return list.reduce((acc, item) => acc + item, 0);
  }, [list]);

  return <div>Total: {total}</div>;
}

useCallback

  • 목적 : 렌더링 시마다 생성되는 함수를 메모이제이션하여, 자식 컴포넌트에 전달하는 콜백함수들이 렌더링될 때마다 새로 생성되는 것을 방지하고 성능을 최적화한다.
  • 사용 예시 : 자식 컴포넌트에 전달되는 함수, 이벤트 핸들러 등을 처리할 때 사용
import React, { useCallback } from 'react';

function ChildComponent({ onClick }) {
  // onClick은 렌더링마다 새로운 콜백이 생성되는 것을 방지
  return <button onClick={onClick}>Click me</button>;
}

function ParentComponent() {
  const handleClick = useCallback(() => {
    console.log('Button clicked');
  }, []); // 의존성 배열이 빈 배열인 경우 항상 동일한 함수를 반환

  return <ChildComponent onClick={handleClick} />;
}
  • 공통점
    • 둘 다 렌더링 성능 최적화를 위해 사용된다.
    • 의존성 배열을 사용하여 해당 값이 변경될 때만 다시 계산하거나 함수를 새로 생성하도록 설정할 수 있다.
  • 차이점
    • useMemo : 주로 값(계산 결과)을 캐싱하고 반환한다.
    • useCallback : 주로 함수를 메모이제이션을 하여 불필요한 함수 생성을 방지한다.
profile
개인 공부용

0개의 댓글