프리온보딩 프론트엔드 챌린지 6월 2회차

흩날리는추억·2024년 6월 9일

✔️ 들어가기 전

1회차에 이어서 2회차에서도 React의 기본적인 내용을 바탕으로 강의가 진행되었습니다. 이번 강의에서는 제가 알지 못했던 내용들도 있어 그 부분을 중심적으로 글을 작성하고 전체적인 내용은 함축하여 기록한 내용입니다.

📑 2회차 강의 내용 목록

  • 상태 관리
  • React Hooks
  • class 컴포넌트의 생명 주기 메서드
  • 상태 관리의 필요성 및 상태 관리 라이브러리 비교

🔎 상태(state)와 속성(props)

상태란?

Component 내부에서 관리하는 데이터로 사용자의 입력이나 네트워크 요청 등으로 변경 가능하며, 이를 통해 실시간으로 UI 업데이트하는데 사용

속성이란?

부모 Component에서 자식 Component로 전달되는 읽기 전용 데이터 이를 통해 자식 Component를 구성하는데 사용

❗ 면접 예상 질문!

  1. 상태와 속성의 차이점은 무엇이며, 각각을 어떻게 활용할 수 있습니까? (나의 답변)
  • 상태란 컴포넌트 내부에서 관리됩니다. 사용자의 입력이나 네트워크 요청과 같은 동적인 내용을 담을 수 있으며, 이를 통해 UI를 실시간으로 업데이트 할 수 있어 좋은 사용자 경험을 할 수 있게 도와줍니다.

  • 속성은 부모 컴포넌트에서 자식 컴포넌트로 전달한 읽기 전용 데이터를 의미합니다. 이를 통해 자식 컴포넌트는 부모의 데이터를 받아 렌더링하는데 사용할 수 있으며, 전달 받은 데이터가 부모 컴포넌트에서 업데이트 될 경우 자식 컴포넌트는 재렌더링을 하게 됩니다.

  1. 상태(state)와 속성(props)을 사용하여 데이터 흐름을 관리하는 방법을 설명하고,그 중요성을 말해보세요.
  • 부모 컴포넌트에서 사용한 상태는 속성을 통해 자식 컴포넌트로 전달 할 수 있습니다. 이를 통해 React는 단방향 데이터 흐름으로 관리하는 것을 알 수 있습니다. 단방향으로 데이터를 관리하면 데이터의 일관성을 유지할 수 있고, 명확한 데이터를 전달 할 수 있습니다. 또한 재사용성도 증가됩니다.

Hooks 탐구

useTransition

애니메이션과 같은 UI 업데이트를 처리할 때 유용한 hook입니다. 상태의 업데이트를 느리게하여, 사용자 인터페이스의 주요 부분이 빠르게 응답할 수 있도록 하고, 이를 통해 사용자 경험을 향상시킵니다.

const [isPending, startTransition] = useTransition();
  • isPending: 트랜지션이 진행 중인지 여부를 나타내는 boolean 값
  • startTransition: 트랜지션을 시작하는 함수, 비동기적으로 상태 업데이트를 수행
import { useState, useTransition } from 'react';

const App = () => {
  const [input, setInput] = useState('');
  const [list, setList] = useState([]);
  // startTransition는 비동기적으로 상태 업데이트를 수행
  const [isPending, startTransition] = useTransition();

  const handleChange = (e) => {
    const value = e.target.value;
    setInput(value);

    // 안의 작업이 끝나면 isPending이 false로 변경
    startTransition(() => {
      const updatedList = Array(20000)
        .fill(0)
        .map((_, index) => `${value} - Item ${index}`);
      setList(updatedList);
    });
  };

  return (
    <div>
      <input type='text' value={input} onChange={handleChange} />
      {isPending ? (
        <p>Loading...</p>
      ) : (
        <ul>
          {list.map((item, index) => (
            <li key={index}>{item}</li>
          ))}
        </ul>
      )}
    </div>
  );
};

useImperativeHandle

부모 컴포넌트가 자식 컴포넌트의 인스턴스 메서드를 명시적으로 호출할 수 있도록 하는데 사용됩니다.

useImperativeHandle(ref, createHandle, [deps])
  • ref: 부모 컴포넌트로 전달된 ref 객체
  • createHandle: 부모 컴포넌트가 자식 컴포넌트에 접근할 수 있는 메서드나 속성을 반환하는 함수
  • deps: 의존성 배열 안의 값이 변경될 때마다 createHandle이 다시 호출
import { useRef, useImperativeHandle, forwardRef, useState } from 'react';

// 자식 컴포넌트
const ChildComponent = forwardRef((props, ref) => {
  const [value, setValue] = useState(0);

  // ref: 부모 컴포넌트와 연결점
  useImperativeHandle(ref, () => ({
    increment: () => setValue((prev) => prev + 1),
    decrement: () => setValue((prev) => prev - 1),
  }));

  return (
    <div>
      <p>Value: {value}</p>
    </div>
  );
});

// 부모 컴포넌트
const ParentComponent = () => {
  const childRef = useRef();

  return (
    <div>
      <ChildComponent ref={childRef} />
      <button onClick={() => childRef.current.increment()}>Increment</button>
      <button onClick={() => childRef.current.decrement()}>Decrement</button>
    </div>
  );
};

useLayoutEffect

useEffect와 유사하지만 DOM 업데이트가 완료된 직후에 동기적으로 실행됩니다. 이 훅은 레이아웃을 읽거나 수정할 때 사용됩니다. useLayoutEffect는 브라우저가 화면을 그리기 전에 실행되므로, 화면이 깜박이는 문제를 방지할 수 있습니다.

useLayoutEffect(() => {
  // DOM 업데이트 직후 실행될 코드
  return () => {
    // 정리 함수 (컴포넌트가 언마운트되거나 effect가 재실행되기 전에 호출)
  };
}, [deps]); // 의존성 배열
import { useState, useRef, useLayoutEffect } from 'react';

const LayoutEffectExample = () => {
  const [rect, setRect] = useState({ width: 0, height: 0 });
  const divRef = useRef(null);

  useLayoutEffect(() => {
    // div의 크기를 측정하고 상태로 저장
    if (divRef.current) {
      const rect = divRef.current.getBoundingClientRect();
      setRect({ width: rect.width, height: rect.height });
    }
  }, []); // 빈 배열을 전달하여 컴포넌트가 처음 렌더링될 때만 실행

  return (
    <div>
      <div ref={divRef} style={{ width: '200px', height: '100px', backgroundColor: 'lightblue' }}>
        Measure me!
      </div>
      <p>Width: {rect.width}px</p>
      <p>Height: {rect.height}px</p>
    </div>
  );
};

❗ 면접 예상 질문!

  1. useEffect와 useLayoutEffect의 차이점은 무엇인가요? (나의 답변)
  • useEffect는 컴포넌트가 렌더링된 후 비동기적으로 실행됩니다. 즉, 브라우저가 화면을 업데이트하고 그린 후에 실행됩니다. 비동기적으로 실행되기 때문에 주로 주로 데이터 가져오기, 구독 설정, DOM 업데이트와 같은 작업에 사용됩니다.

  • useLayoutEffect는 컴포넌트가 렌더링된 후, 브라우저가 화면을 그리기 전에 동기적으로 실행됩니다. 즉, DOM이 업데이트된 직후 바로 실행됩니다. 주로 레이아웃을 측정하고 조정하는 작업에 사용되는데 이를 통해 화면이 그려질 때 필요한 레이아웃 변경을 바로 적용할 수 있습니다.

🔎 class 컴포넌트의 생명주기와 useEffect

class 컴포넌트에 대해 알아두면 좋은점?

  • 회사의 기존 코드가 class로 작성되어 있을 수 있기 때문에 코드 유지보수 할 때 도움이 됨
  • React의 작동 원리에 대해 더욱 깊이 있게 알 수 있음
  • React 면접 대비

생명주기 메서드

class 컴포넌트에서는 componentDidMount, componentDidUpdate, componentWillUnmount 메서드를 사용하여 각각의 라이프사이클 단계에서 특정 작업을 수행할 수 있습니다.

class ExampleComponent extends Component {
  componentDidMount() {
    console.log('Component did mount');
  }

  componentDidUpdate(prevProps, prevState) {
    console.log('Component did update');
  }

  componentWillUnmount() {
    console.log('Component will unmount');
  }

  render() {
    return <div>Example Component</div>;
  }

장점

  • 명확한 라이프사이클 단계: 각 라이프사이클 메서드가 특정 단계에서만 호출되므로, 코드를 읽을 때 컴포넌트의 상태를 쉽게 이해

단점

  • 각 라이프사이클 단계마다 별도의 메서드를 작성하기 때문에 코드가 길어질 수 있음
  • 리액트의 최신 기능을 사용하지 않을 수 있기 때문에 최신 React 개발 트렌드와는 거리가 멀어질 수 있음
  • 상태와 관련 로직을 별도의 함수로 분리하기 어려울 수 있음

useEffect

useEffect는 함수형 컴포넌트에서 사이드 이펙트를 처리하는 데 사용됩니다. 하나의 훅으로 컴포넌트가 마운트될 때, 업데이트될 때, 그리고 언마운트될 때 수행해야 할 작업을 처리할 수 있습니다.

import { useEffect } from 'react';

const ExampleComponent = () => {
  useEffect(() => {
    // 마운트될 때 실행되는 코드
    console.log('Component did mount');

    // 업데이트될 때 실행되는 코드
    console.log('Component did update');

    // 언마운트될 때 실행되는 코드
    return () => {
      console.log('Component will unmount');
    };
  }, []); // 빈 배열이면 마운트와 언마운트 시에만 실행
};

장점

  • 함수형 컴포넌트 내에서 하나의 훅으로 다양한 라이프사이클 단계의 작업을 처리 가능
  • 함수형 컴포넌트의 사용으로 간결하고 직관적인 코드 유지
  • 의존성 배열을 통해 특정 상태나 prop의 변화에만 반응하도록 설정 가능

단점

  • 모든 라이프사이클 로직을 한곳에 관리하기 때문에 로직이 분산되어 가독성이 떨어질 수 있음
  • 클래스 컴포넌트에서 함수형 컴포넌트로 전환하는 경우, 초기에는 useEffect의 사용 방법을 이해하는 데 어려움을 겪을 수 있음

정리

class 컴포넌트와 function 컴포넌트의 차이를 잘 인지하고, 생명주기 메서드와 useEffect의 장단점을 이해하여 면접에 대비!!

🔎 상태 관리의 필요성

  1. 컴포넌트 간의 상태 공유
  2. 상태의 일관성 유지
  3. 복잡한 애플리케이션 구조 관리

React 상태 관리 라이브러리 비교

Context API+ useReducer

  • 단순한 상태관리
  • 추가 라이브러리 불필요
  • 복잡한 상태관리에 한계

Redux

  • 예측 가능한 상태 관리
  • 중앙 집중식 상태
  • 미들웨어를 통한 비동기 작업 관리
  • 보일러 플레이트 코드 많음

Recoil

  • 간단한 사용법
  • 구성 요소 기반 상태 관리
  • 비동기 상태 관리 용이
  • 커뮤니티와 도구가 아직 적음
profile
걱정보다 생각을 하고 싶은 사람

0개의 댓글