[React]구조분해 할당과 React Hook

79ptke·2023년 6월 23일
0

리액트

목록 보기
3/6
post-thumbnail

이번 포스팅을 보시기 전에 이전에 올렸던 자바스크립트 구조분해할당 글을 읽고 오시면 도움이 될 것입니다. 구조분해 할당은 배열이나 객체의 속성을 추출하여 변수에 할당하는 것을 말합니다. 리액트 훅에서도 구조분해 할당을 활용하여 훅의 반환값을 추출하는 경우가 많이 있습니다. 이제부터 본격적으로 리액트 훅과 구조분해 할당에 대해서 알아보도록 하겠습니다.

✅ 1. React Hook

리액트 훅은 리액트 16.8 버전부터 새로 추가가 된 기능며, 클래스 컴포넌트에서 쓰인 기능을 함수 컴포넌트에서 동일하게 쓰일 수 있도록하는 라이브러리입니다. 리액트 훅을 잘 사용하면 더 간단하고 유연한 코드를 작성할 수 있습니다.

리액트 훅을 사용할 때는 몇 가지 규칙이 있습니다.

✔️ React Hook 규칙

1. 최상위에서만 호출

  • 리액트 Hook은 함수형 컴포넌트의 최상위에서만 호출되어야 합니다.
  • 반복문이나 조건문, 중첩 함수 내에서 Hook을 호출하면 안됩니다.
    리액트 훅은 호출되는 순서가 중요합니다. 그래서 반복문이나 조건문, 중첩 함수에서 사용하면 순서가 꼬여서 버그가 발생할 수 있습니다. 위와같은 것을 지키면 Hook의 호출 순서에 일관성이 있고 예측 가능하기 때문에 버그를 예방할 수 있습니다.

2. Hook 호출 순서 지키기

  • 같은 컴포넌트 내에서 여러 개의 Hook을 사용할 때 일관된 순서로 호출이 되어야 관리하는데 어려움이 없습니다.

3. 함수 컴포넌트 내에서만 사용

  • Hook은 일반 자바스크립트 함수나 클래스 컴포넌트에서는 사용할 수 없습니다.
  • 함수형 컴포넌트 또는 Custom Hook에서는 호출이 가능합니다.

4. Hook 이름 규칙

  • 기본적으로 Hook은 "use~~"로 이름이 시작됩니다.
  • Custom Hook 이름 역시 마찬가지로 "use~~"로 이름이 시작됩니다.

5. 조건부 Hook 사용에서의 주의사항

  • 앞에서 말했던 것처럼 호출 순서를 꼬이게 만들 수 있어 조건문 내에서 사용은 불가합니다.
  • 대신 조건부 로직을 Hook 외부로 분리를 해야 합니다.

리액트 훅의 규칙에 대한 설명은 이정도로 하고 이제는 자주 사용하는 리액트 훅에 대해서 알아보겠습니다.

✔️ 자주 사용하는 React Hook

1. useState

  • 상태를 관리하기 위한 Hook입니다.
  • 상태의 초기값을 설정할 수 있으며 처음으로 렌더링 될 때 한 번 사용됩니다.
  • 상태 변수와 상태 업데이트 함수를 제공합니다.
  • setState값과 한 쌍으로 제공됩니다.
  • state는 string,number,boolean,array,null,object 등 다양한 값을 넣을 수 있습니다.

이제 useState에 대한 예시를 보여드리겠습니다.

import { useState } from 'react';

function MyComponent() {
  const [age, setAge] = useState(28);
  const [name, setName] = useState('Taylor');
  const [todos, setTodos] = useState(() => createTodos());
  // ...

useState 변수는 기본적으로 [something, setSomething] 이런 형태를 가지고 있습니다.
처음 배우는 리액트 Hook인만큼 다음 포스팅에서 좀 더 자세하게 다뤄보겠습니다.
이제 다른 리액트 훅에 대해서도 알아보겠습니다.

2. useEffect

  • 어떤 값이 변경될 때마다 특정 코드를 실행하는 Hook입니다.
  • 이를 특정값을 검사한다고 표현합니다.
  • 컴포넌트가 렌더링된 후에 실행되는 코드를 작성할 수 있습니다.
  • 컴포넌트의 state나 props가 변경될 때마다 호출될 수 있습니다.
  • 데이터 가져오기, 구독 설정, 타이머 설정 등의 작업에 사용됩니다.
useEffect(callback, dependencies);

기본적으로 이와 같은 구조로 사용이 됩니다.

useEffect (() => {
    if(!didMountRef.current) {
        return;
    }else {
        console.log("컴포넌트 업데이트");
    }
})

dependencies는 의존성 배열의 형태로 전달됩니다.
두 번째 인수로 전달한 의존성 배열은 요소값이 변경되면 첫 번째 인수로 전달한 callback 함수를 실행합니다. 만약 두 번째 인수의 의존성 배열에 아무것도 전달하지 않으면, useEffect는 컴포넌트를 랜더링 할 때마다 콜백 함수를 실행합니다.

3. useContext

  • 리액트 Context를 사용할 때 사용됩니다.
  • 컴포넌트가 props로 전달하지 않고 먼 부모로부터 정보를 받을 수 있게 해줍니다.
  • 위의 설명에 덧붙이자면 앱의 최상위 컴포넌트는 하위의 모든 컨포넌트가 얼마나 깊게 있든지 상관없이 지금 현재의 ui 테마를 전달할 수 있습니다.
function Button(){
    const theme = useContext(ThemeContext);
    //...
}

4. useReducer

  • 복작합 상태 관리를 위해서 사용되고 있습니다.
  • 상태 관리를 좀 더 구조화하고 컴포넌트의 로직을 분리할 수 있습니다.
const [state, dispatch] = useReducer(reducer, initialState);

기본적인 구조는 이렇게 되어있습니다.
useState와 useReducer를 상황에 맞게 적절하게 사용하면 좋은 코드를 작성할 수 있습니다.

5. useCallback

  • 리렌더링 간에 함수 정의를 캐시할 수 있습니다.
  • 구성요소의 리렌더링을 건너 뛸 때 사용됩니다.
  • 메모화된 callback에서 상태를 업데이트 할 때 사용할 수 있습니다.
  • effect가 자주 발생하지 않도록 할 때도 사용합니다.
  • 직접 만든 Hook을 최적화 할 때도 사용됩니다.
const cashedFn = useCallback(fn, dependencies)

기본적인 구조는 이렇게 됩니다.

const memoizedCallback = useCallback(
  () => {
    doSomething(a, b);
  },
  [a, b],
);

렌더링이 되더라도 함수 값들이 바뀌지 않을 때 함수를 재사용 하도록 하는 데 사용됩니다.

6. useMemo

  • 함수 호출 결과를 저장하고 동일한 입력이 발생할 때 캐시를 사용하여 속도를 높이는 최적화 기술입니다.
  • 비용이 많이 들고 리소스를 많이 사용하는 기능이 불필요하게 실행되지 않도록 하는 데 사용할 수 있습니다.
// React.memo에 대한 예시
function MyComponent(props) {

}
function areEqual(prevProps, nextProps) {

}
export default React.memo(MyComponent, areEqual);

이전과 내용이 바뀌었다면, 값을 연산하고 내용이 바뀌지 않았으면 이전에 연산 값을 재사용합니다.
여기서 주의해야할 점은 성능 최적화로만 사용해야합니다. 렌더링 방지를 하기 위해서는 사용하기 위해서 만들어진 것이 아니기 때문에 그런 용도로 사용하지 말아야합니다.

const App = () => {
  const [count, setCount] = useState(0);
  const [todos, setTodos] = useState([]);
  const calculation = useMemo(() => expensiveCalculation(count), [count]);

  const increment = () => {
    setCount((c) => c + 1);
  };
  const addTodo = () => {
    setTodos((t) => [...t, "New Todo"]);
  };

이렇게 자주 사용하는 리액트 Hook에 대해서 알아보았습니다.

✅ 2. 구조분해 할당

앞에 내용을 작성하면서 구조분해 할당에 대해 간단하게 알아보았는데요.
이번에는 useState를 사용해서 상태를 관리하는 경우에 구조분해 할당을 적용하면 어떻게 되는지 알아보겠습니다.

// useState를 사용
import React, { useState } from 'react';

const MyComponent = () => {
  //count 상태와 setCount 함수를 추출하여 변수에 할당
  const [count, setCount] = useState(0);

  // count 상태를 업데이트하는 함수
  const increment = () => {
    setCount(count + 1);
  };

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

export default MyComponent;

위 예시 코드를 보겠습니다. const [count, setCount] = useState(0); 이 부분은 useState를 사용해서 반환한 값을 배열 구조 분해 할당으로 추출하고, 각각의 count, setCount라는 변수에 할당했습니다. count는 현재 상태의 값이고, setCount는 상태를 업데이트하는 함수입니다.

이렇게 리액트 훅을 사용 시 구조분해 할당을 사용하면 여러 개의 상태를 한 번에 추출할 수 있고, 각각의 변수에 할당할 수 있습니다. 즉, 코드의 가독성과 유지 보수성을 향상시키며 상태 값과 상태를 업데이트 하는 함수를 보다 더 쉽게 다룰 수 있습니다.

이번 포스팅을 이것을 설명을 마치겠습니다.

0개의 댓글