[250328] TIL

오늘 한 일

상태(State) 관리 차이점

클래스형 컴포넌트

  • this.state, this.setState() 사용
  • 모든 상태는 state 객체안에 저장
  • 항상 this 키워드를 사용해야한다.
  • setState()는 객체를 병합한다.
class Counter extends React.Component {
  constructor(props) {
    super(props);
    // state 초기화
    this.state = {
      count: 0,
      name: '홍길동'
    };
  }
  
  incrementCount = () => {
    // setState로 상태 업데이트
    this.setState({ count: this.state.count + 1 });
  }
  
  render() {
    return (
      <div>
        <p>카운트: {this.state.count}</p>
        <p>이름: {this.state.name}</p>
        <button onClick={this.incrementCount}>증가</button>
      </div>
    );
  }
}

함수형 컴포넌트

  • useState hook 사용
    • hook이란 리액트에서 상태관리와 생명주기 기능을 사용할 수 있게 해주는 도구
    • 리액트 16.8 버전에서 도입
  • 각 상태를 독립적으로 관리할 수 있음
  • this 키워드가 필요 없어 더 직관적
  • 상태 업데이트 함수는 이전 상태를 완전히 대체함 (병합 아님)
function Counter() {
  // 각 상태를 개별적으로 선언
  const [count, setCount] = useState(0);
  const [name, setName] = useState('홍길동');
  
  const incrementCount = () => {
    // 상태 업데이트 함수 호출
    setCount(count + 1);
  };
  
  return (
    <div>
      <p>카운트: {count}</p>
      <p>이름: {name}</p>
      <button onClick={incrementCount}>증가</button>
    </div>
  );
}

생명주기 (Lifecycle) 관리 차이점

클래스형 컴포넌트

  • 명확한 생명주기 메서드를 제공한다.
  • 각 단계별로 다른 메서드를 사용함
  • 코드가 분산되어 있어 관련 로직이 여러 메서드에 나뉘어 있을 수 있다.
class DataFetcher extends React.Component {
  constructor(props) {
    super(props);
    this.state = { data: null, loading: true };
  }
  
  // 마운트 시 호출
  componentDidMount() {
    fetch('https://api.example.com/data')
      .then(response => response.json())
      .then(data => {
        this.setState({ data, loading: false });
      });
  }
  
  // 업데이트 시 호출
  componentDidUpdate(prevProps) {
    if (prevProps.id !== this.props.id) {
      this.setState({ loading: true });
      fetch(`https://api.example.com/data/${this.props.id}`)
        .then(response => response.json())
        .then(data => {
          this.setState({ data, loading: false });
        });
    }
  }
  
  // 언마운트 시 호출
  componentWillUnmount() {
    // 정리 작업 (예: 이벤트 리스너 제거, 타이머 정리)
    console.log('컴포넌트가 제거됩니다');
  }
  
  render() {
    return (
      <div>
        {this.state.loading ? '로딩 중...' : this.state.data}
      </div>
    );
  }
}

함수형 컴포넌트

  • useEffect hook 사용해서 생명주기 관리
  • 의존성 배열로 실행 시점을 제어함
  • 관련 로직을 하나의 useEffect 안에 모을 수 있어 응집도가 높습니다.
function DataFetcher({ id }) {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);
  
  // 의존성 배열이 빈 배열일 때 - componentDidMount와 유사
  useEffect(() => {
    fetch('https://api.example.com/data')
      .then(response => response.json())
      .then(data => {
        setData(data);
        setLoading(false);
      });
      
    // 반환되는 함수는 componentWillUnmount와 유사
    return () => {
      console.log('컴포넌트가 제거됩니다');
    };
  }, []); // 빈 배열은 마운트와 언마운트 시에만 실행
  
  // id가 변경될 때마다 실행 - componentDidUpdate와 유사
  useEffect(() => {
    if (id) {
      setLoading(true);
      fetch(`https://api.example.com/data/${id}`)
        .then(response => response.json())
        .then(data => {
          setData(data);
          setLoading(false);
        });
    }
  }, [id]); // id가 변경될 때만 실행
  
  return (
    <div>
      {loading ? '로딩 중...' : data}
    </div>
  );
}

그 외 차이점

메모리 사용과 성능

  • 함수형 컴포넌트는 일반적으로 더 가볍고, 메모리를 덜 사용한다.
  • 클래스형 컴포넌트는 인스턴스를 생성하므로 더 무거울 수 있다.

코드 가독성과 유지보수

  • 함수형 컴포넌트는 일반적으로 코드가 더 짧고 간결함
  • 클래스형 컴포넌트는 this 바인딩 문제로 혼란을 줄 수 있음

로직 재사용

  • 함수형 컴포넌트는 커스텀 훅을 통해 로직을 쉽게 재사용 가능
  • 클래스형은 HOC(고차 컴포넌트)나 render props 패턴을 사용해야함

Categories:

Updated:

Leave a comment