본문 바로가기
🍀오늘도 삽질 중🍀/React.js

React에 대해 알아보자

by 매진2 2023. 10. 16.
728x90

React란?

UI를 구축하기 위한 자바스크립트 프론트엔드 라이브러리

React의 장점

  • virtual DOM을 사용해서 어플리케이션의 성능을 향상시킴
  • 서버, 클라이언트 사이드 렌더링 지원이 가능함
  • 컴포넌트의 가독성이 높고 간단하여 유지보수가 쉬움
  • 다른 프레임워크와도 혼용이 가능

React의 단점

  • 앵귤러와 같은 프레임워크와 비교하자면 리액트는 단순 라이브러리이기 때문에, 더 많은 기능을 사용하고자 한다면 Redux, Router 등 많은 dependencies(의존성 모듈)가 필요
  • 단방향 데이터 바인딩만 제공하는 것이 복잡도를 줄이기 때문에 장점이기도 하지만, 양방향 바인딩에 비해서 더 많은 양의 코드를 작성해야 하므로 불편함

React의 특징

1. 컴포넌트 기반 아키텍처

  • React는 컴포넌트 기반 아키텍처를 사용 -> UI를 작은 재사용 가능한 컴포넌트로 나누어 개발 가능
  • 코드 유지 보수가 더 쉬워지고, 앱 개발이 더 빠르고 효율적으로 진행

2. JSX (Javascript + XML(Extensible Markup Language) )

  • 자바스크립트에 대한 확장 구문으로서, 리액트에서 element(요소)를 제공
  • 개발자가 마크업 코드에 익숙하다면, JSX를 통해 컴포넌트를 구성하는 데 쉽게 적응

3. Vitual DOM

  • 가상돔을 통해 빠른 UI 업데이트와 최적화된 성능을 제공
  • 실제 DOM에 적용되기 전에 변경 사항을 추적하고, 가상 DOM에서 먼저 변경 사항을 적용해 변경 사항이 최소화되므로 성능 향상

4. 단방향 데이터 바인딩

  • 데이터가 한 방향으로만 흐르는 것을 의미
  • 상태 관리를 보다 쉽게 만들며, 데이터를 추적하고 관리 용리
  • UI 수정과 재사용성이 좋으며, 코드 가독성 ↑

⭐️ React의 사용이유

  • 동적 페이지의 유저 인터페이스를 효율적으로 유지보수 및 관리
  • 컴포넌트 기반 아키텍처-> 재사용 가능한 컴포넌트를 개발해 생산성이 높고 유지보수가 용이
  • HTML 문법과 유사한 JSX를 사용하기 때문에, HTML을 작성하듯 코드를 작성할 수 있어 편리하며 가독성↑
  • 가상 DOM을 사용해서, 최종적인 변화만을 실제 DOM에 전달하기 때문에 연산 비용이 적은 편

=> 리액트는 자기만의 문법을 가진 앵귤러나 뷰와는 다르게 대부분 자바스크립트의 문법을 그대로 활용

=> 가장 많이 사용 중

=> UI를 자동으로 업데이트


리액트의 내부 작동 원리

Reconciliation

실제로 DOM을 제어하지 않고 중간에 virtual DOM을 두어 virtual DOM이 변경될 때, 실제 DOM을 변경하도록 설계

 

virtual DOM을 갱신하는 방법

1. setState()메소드를 호출하는 방법

2. redux의 경우처럼 store가 변하면 다시 최상위 컴포넌트의 render()함수를 호출해서 갱신하는 방법


⭐️ 리액트의 라이프 사이클

  1. 마운트 (Mounting): 컴포넌트가 생성되고 DOM에 추가될 때의 단계입니다.
    • constructor
    • static getDerivedStateFromProps
    • render
    • componentDidMount : 최초로 컴포넌트 객체가 생성될 때 한 번 수행
  2. 업데이트 (Updating): 컴포넌트가 업데이트되는 단계입니다.
    • static getDerivedStateFromProps
    • shouldComponentUpdate
    • render : 초기에 화면을 그려줄 때와, 업데이트가 될 때 호출
    • getSnapshotBeforeUpdate
    • componentDidUpdate : 컴포넌트의 속성 값 또는 상태값이 변경되면 호출
  3. 언마운트 (Unmounting): 컴포넌트가 DOM에서 제거되는 단계입니다.
    • componentWillUnmount : 컴포넌트가 소멸될 때 호출
  4. 오류 처리 (Error Handling): 컴포넌트 내부에서 오류가 발생했을 때의 처리를 담당합니다.
    • static getDerivedStateFromError
    • componentDidCatch

⭐️ 생명주기 메소드란?

컴포넌트가 브라우저 상에서 나타날 때, 업데이트 될 때, 사라지게 될 때 호출하는 메소드

컴포넌트 사이클 : 마운트 - 업데이트 - 언마운트

 

생명주기 메소드 종류

  • componentWillMount: 컴포넌트가 생성된 후 DOM에 렌더링되기전 호출됩니다.
  • componentDidMount: 첫 렌더링이 끝나고 컴포넌트의 DOM 엘리먼트가 사용가능할 시 호출됩니다.
  • componentWillReceiveProps: props가 업데이트 될 때 호출됩니다.
  • shouldComponentUpdate: 새로운 props를 받았을 때 호출되며, 성능 최적화를 위해 재렌더링을 막을 수 있습니다.
  • componentWillUpdate: 새로운 props를 받았고 shouldComponentUpdate가 true를 리턴할 때 호출됩니다.
  • componentDidUpdate: 컴포넌트가 업데이트된 후에 호출됩니다.
  • componentWillUnmount: 컴포넌트가 DOM에서 제거되기 전 호출되어 이벤트 리스너 등을 정리할 수 있게 해줍니다.

함수형 컴포넌트에서는 useEffect라는 훅을 이용해서 생명주기 메소드들을 대체

useEffect(callBackFunc); //렌더링 될 때마다
useEffect(callBackFunc, []); // componentDidMount : 최초 렌더링시
useEffect(callBackFunc, [state1, state2]); // 최초 렌더링 + dependencies가 변경 되었을 때
useEffect(()=>{ return(() => func()) }); // componentWillUnmount

shouldComponentUpdate란?

Pure component란?

  • 컴포넌트가 성능 최적화를 위해 상태 및 속성 변경에 의해 리렌더링되지 않을 때
  • shouldComponentUpdate 메서드를 자동으로 구현하여 성능 향상을 위해 리렌더링을 방지

Pure component 특징

  • Side Effects가 없음
  • 동일한 입력에 대해 항상 동일한 결과를 반환
  • 재사용성 용이
  • 함수형 프로그래밍

shouldComponentUpdate의 역할

컴퓨터에게 언제 화면을 다시 그릴지를 결정하는데 도움

전체 렌더링인지 부분렌더링인지 구분함


⭐️ Flux 패턴 모델

Flux패턴

  • 단방향 데이터 흐름을 사용하여 Action -> Dispatcher -> Store -> View의 방향으로 데이터가 흐름
  • Flux에서는 Store가 애플리케이션의 데이터와 비즈니스 로직을 담당, Dispatcher를 통해 Action을 처리
  • 단방향 데이터 흐름과 단일 책임 원칙을 따르므로 테스트하기 쉬운 코드를 작성 용이 
  • React에서 주로 사용

MVVM패턴

  • 데이터 바인딩을 사용하여 View와 ViewModel 간에 양방향 데이터 흐름을 유지
  • MVVM에서는 ViewModel이 Model의 역할을 수행, View와 ViewModel 사이에서 데이터를 중개
  • MVVM에서는 ViewModel과 View 간의 양방향 데이터 바인딩 때문에 테스트하기가 어려움
  • Angular, Vue.js 등의 프레임워크에서 사용

반응형 웹 디자인 VS 적응형 웹 디자인

 


함수형 프로그래밍이란?

프로그래밍 패러다임이란?

프로그래머에게 프로그래밍의 관점을 갖게 하고, 결정하는 역할

종류 : 명령형 프로그래밍, 선언형 프로그래밍

 

왜 함수형 프로그래밍을 배워야 할까?

함수형 프로그래밍하는 사고를 배움 => 다양한 사고방식으로 프로그래밍을 바라보면 더욱 유연한 문제해결이 가능

 

함수형 프로그램이에 필요한 개념

1급 객체, 고차 함수, 불변성, 순수 함수, 데이터 변환 방법, 합성 함수

 

어떻게 함수형 프로그래밍을 구현할까?

1. 순수 함수를 조합하고, 공유 상태, 변경 가능한 데이터 및 부작용을 피하여 소프트웨어를 만드는 프로세스
2. 함수형 프로그래밍은 명령형이 아닌 선언형이며 애플리케이션의 상태는 순수 함수를 통해 전달


CSR과 SSR

CSR (Client Side Rendering)이란?

  • CSR은 클라이언트 측에서 웹 페이지를 렌더링하는 방식
  • 웹 페이지의 초기 로딩 시, HTML 및 기본적인 자바스크립트만 서버로부터 받아온 후, 브라우저에서 자바스크립트가 실행되어 동적 컨텐츠를 생성
  • CSR은 브라우저에서 렌더링되므로, 웹 애플리케이션의 초기 로딩 속도는 빠르지만, 검색 엔진 최적화(SEO)에 대한 처리가 필요
  • 초기 페이지 로딩 이후 추가 데이터를 불러오는데 시간이 소요될 수 있음

SSR (Server Side Rendering)이란?

  • SSR은 서버 측에서 웹 페이지를 완전히 렌더링한 후 브라우저로 전송하는 방식
  • 서버에서 HTML과 동적 컨텐츠를 렌더링하여 클라이언트로 보내면, 초기 로딩 시에 렌더링된 페이지가 브라우저에 나타남
  • SSR은 검색 엔진 최적화(SEO)에 유리하며 초기 로딩 속도가 빠름
  • 서버 부하가 크고, 더 복잡한 웹 애플리케이션 구현이 필요

CSR은 초기 로딩 속도가 빠르지만 SEO에는 취약

SSR은 초기 로딩 속도는 느릴 수 있지만 SEO와 검색 엔진에서 페이지 콘텐츠를 쉽게 인식

==> 선택은 웹 애플리케이션의 요구 사항과 성능 목표에 따라 다름


⭐️ Virtual DOM이란?

Virtual DOM은 애플리케이션의 UI를 구성하는 HTML 요소들을 메모리 내에서 구현한 것

 

⭐️ 작동 원리

컴포넌트가 재 렌더링이 될 때, Virtual DOM은 업데이트할 요소의 목록들을 만들기 위해 기존의 가상돔과 변경된 사항을 비교, 변경된 부분만 업데이트

=> DOM 전체를 다시 렌더링할 필요가 없기 때문에 DOM에 필요한 최소한만을 변경하여 효율성


컴포넌트란?

레고 블록과 같이 작은 단위로 만들어져서 그것을 조립하듯이 개발하는 방법

캡슐화, 확장성, 결합성, 재사용성과 같은 이점이 있음

 

리액트는 컴포넌트 기반 아키텍처라던데?

  • 리액트에서 컴포넌트는 애플리케이션 UI 구축의 기반
  • 컴포넌트 기반 시스템이 구축되면, 각각의 개별적인 구성 요소들은 재사용이 가능하며 서로 독립적으로 존재
  • 즉 구성 요소 간 서로 의존하지 않으며 애플리케이션의 UI 개발 용이

⭐️ 클래스 컴포넌트와 함수형 컴포넌트

1. 클래스 컴포넌트

class Welcome extends React.Component {
	render() {
    	return <h1> Hello, {this.props.name} </h1>;
    }
}
  • React 16.8(Hooks의 도입) 이전에는 내부 상태를 유지하는 데 필요한 컴포넌트를 생성하거나 생명주기 메소드를 활용하기 위해 클래스 기반 컴포넌트를 사용
  • 클래스 기반 컴포넌트는 리액트의 컴포넌트 클래스를 확장하는 ES6 클래스이고, 항상 render() 메소드를 포함
  • 클래스 기반 컴포넌트들은 마운트되었을 때나 언마운트될 때와 같이 생명주기 중 특정 시점에 호출되는 특별한 메소드를 선언 가능

=> 컴포넌트가 필요할 때 세팅 및 해체, 타이머를 설정하거나 브라우저 이벤트에 바인딩할 시 유용

 

기존의 클래스형 컴포넌트에서는 몇 가지 어려움이 존재한다.

  1. 상태(State) 로직 재사용 어려움
  2. 코드가 복잡해짐
  3. 관련 없는 로직들이 함께 섞여 있어 이해가 힘듬

이와 같은 어려움을 해결하기 위해, 'Hook'이 도입되었다. (16.8 버전부터)

 

2. 함수 컴포넌트

function Welcome(props) {
	return <h1>Hello, {props.name}</h1>
    }

(Hooks 도입 이전의) 함수형 컴포넌트는 state를 갖지 않으며 렌더링할 출력 결과를 리턴

함수형 컴포넌트는 클래스 컴포넌트보다 간단하기 때문에 props에만 의존하는 UI를 렌더링하는데 선호

 

hook 도입 이후로 함수형 컴포넌트에서도 내부 상태 관리와 생명주기 메소드를 사용 가능

또한 커스텀훅을 통해 재사용성 있는 함수를 여러 컴포넌트에서 쉽게 사용 가능

 

함수형 컴포넌트의 장점

  • 클래스형 컴포넌트보다 선언이 간편
  • 클래스형 컴포넌트보다 메모리 자원을 덜 사용함
  • 프로젝트 빌드 후 배포할 때 결과물의 파일 크기가 더 작음
  • 이전에는 라이프사이클 API를 사용하지 못한다는 단점이 있었는데, 이제는 16.8부터 지원하는 Hook을 통해 이러한 단점 사라짐

React에 hooks을 도입해 얻을 수 있는 이점

  • 클래스 기반 컴포넌트, lifecyle hooks, this의 필요성이 사라짐
  • 공통 기능을 커스텀 hook으로 만들어서 로직을 재사용하기 쉬움
  • 컴포넌트 자체에서 로직을 분리할 수 있어서 읽기 쉽고 테스트하기 쉬운 코드를 작성 가능

클래스 컴포넌트와 함수 컴포넌트의 차이

  • 클래스형 컴포넌트와 함수형 컴포넌트의 가장 큰 차이점은 상태와 생명주기의 다루는 방식
  • 클래스형 컴포넌트는 상태를 this.state로 정의하고, 생명주기 메서드를 오버라이드하여 다양한 작업을 수행
  • 반면에 함수형 컴포넌트는 상태를 useState 훅을 사용하여 정의하고, useEffect 훅을 사용하여 생명주기를 다룸
  • 클래스형 컴포넌트에서는 this 키워드를 사용하여 상태나 메서드를 참조
  • 함수형 컴포넌트에서는 this 키워드를 사용 안함
  • ===> 함수형 컴포넌트는 더 간결하고 가독성이 좋아지며, 테스트와 리팩토링이 쉬움
  1. 구현 방식 및 문법:
    • 함수형 컴포넌트:
      • 함수형 컴포넌트는 함수로 구현되며, JSX를 반환하는 형태로 UI를 정의합니다.
      • 단순하고 간결한 문법을 가지고 있으며, 가독성이 좋습니다.
      • React 함수형 컴포넌트는 순수 JavaScript 함수입니다.
    • 클래스 컴포넌트:
      • 클래스 컴포넌트는 ES6 클래스를 사용하여 구현됩니다.
      • render() 메서드를 통해 JSX를 반환하고, extends React.Component로 React 컴포넌트 클래스를 상속합니다.
      • React 클래스 컴포넌트는 JavaScript 클래스입니다.
  2. 상태 관리:
    • 함수형 컴포넌트:
      • 초기에는 함수형 컴포넌트에서는 상태(state)를 관리할 수 없었지만, React Hook을 사용하여 함수형 컴포넌트에서도 상태를 관리할 수 있게 되었습니다.
      • useState 훅을 사용하여 함수형 컴포넌트 내에서 상태를 선언하고 업데이트할 수 있습니다.
    • 클래스 컴포넌트:
      • 클래스 컴포넌트에서는 this.state 객체를 사용하여 상태를 관리하고, this.setState 메서드를 사용하여 상태를 업데이트합니다.
  3. 생명주기 관리:
    • 함수형 컴포넌트:
      • React 16.8 이후, 함수형 컴포넌트에서는 Hook을 사용하여 생명주기와 관련된 작업을 처리할 수 있습니다.
      • 예를 들어 useEffect Hook을 사용하여 컴포넌트가 렌더링될 때, 업데이트될 때, 혹은 언마운트될 때 특정 동작을 수행할 수 있습니다.
    • 클래스 컴포넌트:
      • 클래스 컴포넌트에서는 생명주기 메서드(componentDidMount, componentDidUpdate, componentWillUnmount 등)를 사용하여 생명주기 관리를 합니다.
  4. 코드의 길이와 가독성:
    • 함수형 컴포넌트:
      • 주로 간결하고 작은 코드로 작성할 수 있어 가독성이 좋습니다.
      • 함수형 프로그래밍 스타일에 기반하므로 부수 효과를 줄이고 불변성을 지향합니다.
    • 클래스 컴포넌트:
      • 클래스 정의, 생성자, 렌더 메서드, 생명주기 메서드 등이 필요하므로 코드가 상대적으로 길어질 수 있으며, 가독성이 떨어질 수 있습니다.
  5. 성능:
    • 함수형 컴포넌트:
      • 최신 버전의 React에서 함수형 컴포넌트와 클래스 컴포넌트 간의 성능 차이가 크게 줄어들었습니다.
      • React Hook을 통한 최적화 기법을 적용하여 함수형 컴포넌트의 성능을 최적화할 수 있습니다.
    • 클래스 컴포넌트:
      • 이전에는 클래스 컴포넌트가 조금 더 무거웠지만, 최신 React에서는 함수형 컴포넌트와 성능 차이가 크게 줄어듦에 따라 성능 차이가 미미해졌습니다.

HOC (Higher Order Components 고차 컴포넌트)란?

  • 반복되는 컴포넌트 로직을 쉽게 재사용하기 위한 기술로서, 컴포넌트를 취하여 새로운 컴포넌트를 반환하는 함수
  • HOC은 컴포넌트를 인자로 전달 받고 전달 받은 컴포넌트를 기반으로, 전달 받은 props와 HOC 내부에서 추가적으로 생성한 props를 주입한 새로운 컴포넌트를 반환
  • Container HOC를 제외하고, 보통 HOC를 통해 새로운 prop을 주입 할 때 많이 사용 하는 규칙은 with로 시작하여 withNewPropName 식으로 네이밍함

고차 컴포넌트 예시

1. 로딩 중 화면 표시

보통 SPA(Single Page App)에서 화면이 로딩 중일 때, Skeleton 화면을 보여주고, 로딩이 완료되면 데이터를 보여줄 때 사용

2. 유저 인증 로직 처리

컴포넌트 내에서 권한 체크나 로그인 상태를 체크하기 보다는 인증 로직을 HOC로 분리하면 컴포넌트 재사용성도 높일 수 있고, 컴포넌트에서 역할 분리도 쉽게 할 수 있음.

3. 에러 메세지 표시

컴포넌트 내에서 분기문(if/else 등)을 통해 처리 할 수도 있지만, 분기문을 HOC로 만들어 처리 하면 컴포넌트를 더욱 깔끔하게 사용 가능

 

Functional Component를 리턴

const withHOC = WrappedComponent => {
  const newProps = {
    loading: false,
  };
  return props => {
    return <WrappedComponent {...props} {...newProps} />
  }
};

Class Component를 리턴

const withHOC = WrappedComponent => {
  const newProps = {
    loading: false,
  };
  return class extends React.Component {
    render() {
      return <WrappedComponent {...this.props} {...newProps} />
    }
  }
};

⭐️ 제어 비제어>>>>>>>>내용 추가 예정

HTML 문서의 많은 form 엘리먼트들은 고유한 상태를 유지합니다.

비제어 컴포넌트는 DOM에 이러한 input들의 상태에 대한 값들을 source of truth로 취급합니다.

제어 컴포넌트에서 내부 상태는 엘리먼트의 값을 추적하기 위해 사용합니다.

input의 값이 변경되면 리액트는 input을 재 렌더링합니다. 비제어 컴포넌트는 리액트가 아닌 코드와 합쳐질 때 유용하게 사용될 수 있습니다.


⭐️ JSX 문법 JavaScript XML(eXtensible Markup Language)

JSX란?

HTML처럼 보이는 코드를 작성할 수 있게 해주는 자바스크립트 문법의 확장자

자바스크립트 함수 호출 방식으로 컴파일되어 컴포넌트에 대한 마크업을 만들 수 있는 방법을 제공

 

작동방식

  • 브라우저는 JSX 파일을 직접 읽을 수는 없다. 브라우저가 JSX 파일을 읽으려면 JSX를 자바스크립트 객체로 변환을 해야 한다. 그리고 그 변환 작업은 바벨과 같은 컴파일러를 통해 이루어진다.
  • 여기서 기존에 JSX를 사용한 파일 내에서 React를 import 했던 이유를 알 수 있다. 컴파일러를 통해 JSX 코드가 자바스크립트 코드로 변환이 되면, 아래와 같이 React.createElement()로 변환이 된다.
  • 즉, React.createElement()가 정상적으로 호출되기 위해 React가 스코프에 존재해야 하는 것이다.
  • 기쁜 소식은! 2020년 10월 20일에 릴리즈 된 React 17부터는 JSX 변환에 대비하여 React를 import 하지 않아도 되게 되었다. 왜냐하면 React 17에선 바벨과 같은 컴파일러를 사용하여 JSX를 변환할 때 React.createElement로 변환하는 것이 아닌 다른 방식으로 변환하는 방식을 도입했기 때문이다. 이 새로운 방식에선 아래 코드와 같이, 컴파일러가 JSX 변환에 필요한 특수한 함수를 자동적으로 import 해오기 때문이다. (다만 훅이나 React가 제공하는 다른 기능들을 사용할 땐 여전히 React를 import 해야 한다.)

사용방식

  • JS 문법 넣을 경우 : { }
  • event 네이밍 : onClick
  • 속성명은 camelCase로 작성
  • Self-Closing Tag
  • <React.Fragment>

렌더링

  • 리액트에서 렌더링은 render() 함수를 통해 이루어지는데, 이 함수가 호출되면 DOM 요소를 나타내는 요소가 반환
  • 한번에 둘 이상의 HTML 요소를 렌더링하는 것도 가능->HTML 요소들을 여는 태그, 닫는 태그로 감싸면, 즉 enclosing tag로 감싸면 여러 요소를 동시에 렌더링 가능

CRA란?

CRA(create-react-app)란?

  • React의 공식 CLI(명령줄 인터페이스)로서, SPA 개발 초기 세팅을 편리하게 할 수 있도록 도와줌
  • 애플리케이션을 개발할 때 create-react-app을 사용하면 개발자가 빌드 구성을 직접 하지 않아도 되기 때문에 코드에만 집중할 수 있어 효율적으로 개발 가능
  • Create React App (CRA)를 사용하여 React 애플리케이션을 시작하면 Babel과 다른 필수 도구가 자동으로 설정되고 구축
  • CRA를 사용하면 Babel, Webpack, ESLint 및 기타 관련 도구가 포함된 개발 환경이 미리 구성

CRA로 새로운 React 프로젝트를 시작했을 때 Babel의 역할

  1. JSX를 JavaScript로 변환
  2. 최신 ECMAScript 표준을 이전 버전으로 변환
  3. 기타 JavaScript 확장 및 구문을 처리

Babel이란?

  • JavaScript 컴파일러, 최신 버전의 JavaScript로 코드를 작성하는데 도움이 되는 도구
  • JavaScript의 버전업그레이드로 인한 최신 문법을 가진 ES6+ 코드를 런타임 환경인 브라우저가 인식하고 실행하는데 문제가 생기고 효율성과 유지보수등의 이유로 코드는 ES6+ 로 구현해야 하는데 실행환경인 모든 브라우저가 최신 문법을 다 지원하지 못하기에 버전 차이가 발생하게 됩니다.  이러한 문제를 해결해 주는게 Babel
  • Babel은 이러한 기능을 수행하기 위해 다양한 플러그인(plugin)을 제공->이 플러그인들은 각각 다른 역할을 수행하며, 코드를 변환할 때 적용 가능 또한,
  • Babel은 빌드 도구(build tool)와 연동하여 자동으로 코드 변환 작업을 수행할 수 있도록 해주는 기능도 제공
  • Babel은 React, Vue, Angular 등의 모던 프론트엔드 프레임워크와 함께 사용되어, 최신 JavaScript 기능을 활용한 모던한 웹 애플리케이션 개발을 가능하게 해줌

HOOKS

Hook이란?

리액트 hook은 React 16.8버전에 새로 추가된 기능

함수형 컴포넌트에서 react state와 생명주기 기능( lifecycle features )을 "연동(hook into)할 수 있게 해주며 useState를 예시로 들면 class를 사용하지 않고도 상태를 가질 수 있게 된 것

또한 props, state, context, refs 그리고 lifecycle과 같은 리액트 개념에 좀 더 직관적인 API를 제공

 

Hook의 장점

로직의 재사용이 가능하고 관리가 쉽다는 것

-> 함수 안에서 다른 함수를 호출하는 것으로 새로운 hook을 만들어 볼 수 있습니다. 기존의 class component는 여러 단계의 상속으로 인해 전반적으로 복잡성과 오류 가능성을 증가시켰습니다. 하지만 function component에 hooks에 도입되면서 class component가 가지고 있는 기능을 모두 사용할 수 있음은 물론이고 기존 class component 복잡성, 재사용성의 단점들까지 해결됩니다.

React에서 제공하는 기본적인 Hook

1. useState

  • 동적으로 바뀌는 값을 관리할 때 사용
  • useState 함수는 배열을 반환하며, 첫 번째 요소는 현재 상태 값을, 두 번째 요소는 상태 값을 변경할 수 있는 함수를 반환
  • const, let 등으로 선언한 변수와 다르게 값이 변하면 관련 있는 컴포넌트들이 재렌더링되어 화면이 바꿥니다.
  • let 대신 const 쓰는 이유 : 변수의 재할당 막기위해

2. useEffect

  • 리액트 컴포넌트가 렌더링될 때마다 특정 작업을 실행할 수 있도록 하는 hook
  • 함수형 컴포넌트에서 생명주기 메서드를 사용하기 위한 Hook
  • Side Effect를 함수형에서 사용할 수 있게 하는 리액트 hooks
  • useEffect 함수는 컴포넌트가 렌더링 될 때마다 실행되며, 해당 컴포넌트가 마운트될 때, 업데이트될 때, 언마운트될 때 등 다양한 타이밍에 실행 가능
  • dependency array : 의존성 배열 참조하여 실행 시기 조정

useEffect로 componentWillUnmount가 동작할 수 있는 방법

  • componentWillUnmount : 컴포넌트가 화면에서 사라질 때 나타나는 라이프사이클
  • useEffect 코드 내부에서 return하는 익명함수를 작성하는 방법으로 componentwillUnmount를 구현
useEffect(() => {
    console.log('컴포넌트가 화면에 나타남');
    return () => {
      console.log('컴포넌트가 화면에서 사라짐');
    };
  }, []);

 

useEffect와 useLayoutEffect의 차이점

useEffect

  • 비동기적으로 부수 효과를 처리
  • 컴포넌트가 렌더링된 후에 실행되며, 화면 업데이트와 관련이 없는 작업들을 처리할 때 주로 사용
  • 예를 들어, 데이터를 가져오거나 구독을 설정하는 등

useLayoutEffect

  • 동기적으로 부수 효과를 처리
  • 컴포넌트가 렌더링되고, 화면이 업데이트되기 전에 실행
  • 주로 화면 업데이트와 관련이 있는 작업들을 처리할 때 사용
  • 레이아웃 계산이 필요한 작업에 유용

 

3. ⭐️ React.memo, useMemo, useCallback

React.memo, useMemo, useCallback은 모두 불필요한 렌더링 또는 연산을 제어하는 용도로 성능 최적화에 목적

React.memo는 HOC이고, useMemo와 useCallback은 hook

===>

React.memo는 HOC이기 때문에 클래스형 컴포넌트, 함수형 컴포넌트 모두 사용 가능

useMemo, useCallback는 hook이기 때문에 함수형 컴포넌트 안에서만 사용 가능

useMemo는 함수의 연산량이 많을때 이전 결과값을 재사용하는 목적

useCallback은 함수가 재생성 되는것을 방지하기 위한 목적

 

메모이제이션이란?

이전에 계산한 결과를 저장하고, 동일한 입력에 대한 계산을 다시 수행하지 않고 이전 결과를 재사용함으로써 성능을 향상시키는 방법

리액트는 값이 변할 때마다 리렌더링 -> 의도치 않게 리렌더링이 계속 일어나 성능이 저하되는 것을 해결하기 위해서 메모제이션 기법 사용

대표적인 훅 : useMemo, useCallback

 

3-1. React.memo

  • React.memo는 Higher-Order Components(HOC)
  • 하나의 컴포넌트가 똑같은 props를 넘겨 받았을 때 같은 결과를 렌더링 하고 있다면 React.memo를 사용하여 불필요한 컴포넌트 렌더링을 방지
  • React.memo를 사용할 경우 이전과 같은 props가 들어올때는 렌더링 과정을 스킵하고 가장 최근에 렌더링된 결과를 재사용

React.memo의 사용법

export default React.memo(component);

3-2. useMemo

  • 메모제이션된 객체 값을 리턴
  • 함수가 호출 될 때마다 새로 객체를 생성하는 것이 아니라 dependency의 값이 변경되었을 때만 새로 객체를 생성

useMemo 사용법

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

useMemo와 useRef와의 차이

useMemo : deps가 변경되기 전까지 값을 기억하고, 실행후 값을 보관하는 역할로도 사용, 복잡한 함수의 return 값을 기억

=> useRef : 특정 값을 기억하는 경우

=> useMemo는 복잡한 함수의 return값을 기억하는 경우

 

useCallback

  • 메모제이션된 함수를 리턴
  • 변수가 선언되어지면 해당 함수가 실행
  • 그 후에 deps의 변경을 통해 값이 변경이 되면 새로운 함수를 return하고, 값이 변경이 되어지지 않는 다면 기존 함수를 return
  • useCallback 함수는 첫 번째 인수로 입력된 콜백의 메모이제이션 버전을 반환
  • 반환된 메모이제이션 버전은 콜백의 의존성이 변경되었을 때만 변경되며, 이는 불필요한 렌더링을 방지하기 위해 참조의 동일성에 의존적인 최적화된 자식 컴포넌트에 콜백을 전달할 때 유용
  • 예로 React의 Memo로 감싸진 컴포넌트에 프롭으로 전달하는 경우, 자주 사용

4. useRef

  • .current 프로퍼티로 전달된 인자로 초기화된 변경 가능한 ref 객체를 반환
  • 이 객체는 컴포넌트의 전 생애주기를 통해 유지됨
  • 이 전 생애주기를 통한 유지란 컴포넌트가 리렌더링되어도 값이 유지가된다는 뜻

 

5. useContext

컴포넌트 트리 안에서 전역적으로 상태를 관리하기 위한 Hook

createContext를 통해 생성한 Context 객체를 사용하여 컴포넌트 간에 값을 공유

⭐️ 리액트 렌더링 성능 향상을 위한 방법

컴포넌트 리렌더링 되는 조건

  • 부모에서 전달 받은 props가 변경될 때
  • 부모 컴포넌트가 리렌더링될 때
  • 자신의 state가 변경될 때

리렌더링을 줄여 성능을 향상 시키자

1. useMemo 사용하기

  • 컴포넌트가 리렌더링될 때마다 함수가 호출되는 것을 방지
  • 종속 변수들이 변하지 않으면 이전에 반환한 참조값을 재사용

2. react.memo 컴포넌트 메모제이션

  • 컴포넌트의 props가 바뀌지 않았다면, 리렌더링하지 않도록 설정

3. useCallback 사용하기

  • 함수 선언을 메모이제이션

4. 자식 컴포넌트의 props로 객체를 넘겨줄 경우 변형하지 말고 넘겨주기

  • 새로 생성된 객체를 전달하면 컴포넌트가 리렌더링될 때마다 새로운 객체가 생성되어 전달
  • 새로 생성된 객체는 이전 객체와 다른 참조 주소를 가진 객체이기 때문에 자식 컴포넌트는 메모제이션이 되지 않음

5. 컴포넌트를 매핑할 때 key 값으로 index를 사용하지 않는다.

  • 배열 중간 요소가 변경되면 그 뒤에 요소들도 index가 다 변경되기 때문

6. useState의 함수형 업데이트

  • useCallback에 depency 배열을 비워 사용

리액트에서 상태(state)란?

상태란?

  • 컴포넌트의 동작 및 렌더링과 같은 부분을 제어하는 데이터 또는 객체
  • 상태를 이용하여, 동적이고 인터랙티브한 컴포넌트를 쉽게 개발 가능
  • state는 컴포넌트의 생명주기 동안에 수정될 수 있는 내부 데이터로, 재 렌더링시에도 유지

state를 직접 바꾸지 않고 setstate를 사용하는 이유

=> 불변성 유지

불변성 유지 : useState로 생성된 상태 변수를 업데이트할 때는 상태를 직접 변경하지 않고 새로운 상태를 반환하는 방식으로 업데이트

불변성을 유지하면 React가 상태 변경을 감지할 때 더 효과적으로 작동, 예기치 않은 부작용을 방지


리액트에서 props란 무엇인가?

props란?

  1. props는 프로퍼티(properties, 속성)의 줄임말로, 읽기만 가능하며(read-only) 불변성을 지닌 요소
  2. 애플리케이션에서 props는 부모 컴포넌트로부터 자식 컴포넌트로 전달되는 계층 구조를 따르며 반대는 불가능 <- 리액트는 단방향 데이터 흐름 모델을 사용하기 때문

key prop

  • 리액트에서 collection을 렌더링할 때 요소와 데이터 사이의 관계를 추적하기 쉽도록 반복되는 각 요소에 key를 추가하는 것이 중요
  • 키는 고유한 ID(이상적으로는 uuid 또는 기타의 고유한 문자열)을 사용
  • 마지막 수단으로 Array index를 사용 가능
  • => 요소가 삭제, 추가 되면서 index 값이 변경될 수 있기 때문에 리액트 공식문서에서는 index를 지양
  • key를 사용하지 않으면 collection에 아이템을 추가하거나 제거할 때 예상하지 못한 동작 결과가 발생

prop drilling

  • 부모 컴포넌트에서 하위 컴포넌트로 데이터를 전달할 때 발생하는 것
  • props를 전달하는 것 이외에는 props를 필요로 하지 않는 다른 컴포넌트를 통해 "drilling"이 됨
  • 이를 해결하기 위해 전역 상태 관리 라이브러리인 Redux, Mobx를 이용하여 해당 값이 필요한 컴포넌트에게 직접 불러서 사용

화살표 함수 >>>>>>>>>내용 추가 예정

  • 클래스형 컴포넌트 내에서는 bind를 사용하여 this 바인딩을 따로 해주어야 함
  • 화살표 함수를 사용한다면 this 바인딩을 따로 해주지 않아도 돼서 편리함

⭐️ Context API

하나의 애플리케이션 안에서 다수개의 컴포넌트들이 상태를 공유할 때 발생하는 문제들에 대해 대응

소규모의 앱에서는 Redux가 불필요한 복잡성을 유발한다고 느껴 context api 사용


Redux

Redux란?

JavaScript 애플리케이션 상태 관리 라이브러리

예측 가능한 상태 컨테이너를 제공하여 애플리케이션의 상태를 관리하고 업데이트하는 데 도움

주요 목표는 상태 관리를 단순화하고 효율적으로 만드는 것

Redux의 구성

1. Store (스토어)

  • 애플리케이션의 전체 상태를 담고 있는 객체
  • 이 상태는 읽기 전용
  • 애플리케이션의 모든 상태는 스토어에서 관리

2. Actions (액션)

  • 상태를 변경하는 작업을 나타내는 객체
  • 일반적으로 JavaScript 객체로 표현
  • "type" 필드를 가지고 있어 어떤 작업을 수행할 것인지 식별

3. Reducers (리듀서)

  • 액션을 기반으로 이전 상태와 액션을 사용하여 새로운 상태를 생성하는 순수 함수
  • 리듀서는 상태의 변경을 관리하고 업데이트

4. Dispatch (디스패치)

  • 액션을 스토어에 보내는 메서드
  • 스토어의 상태를 변경하고 컴포넌트에 새로운 데이터를 전달

5. Subscribe (구독)

  • 스토어 상태의 변경을 감지하고, 상태가 변경될 때 특정 함수를 호출하는 메서드

리덕스 쓰는 이유

복잡한 애플리케이션 상태를 효과적으로 관리

state를 수정하는 것을 한 곳에서 관리가 가능해지기 때문에 상태 변화를 예측 가능하게 만들 수 있음

다양한 컴포넌트 간의 상태 공유와 통신을 단순화

리덕스를 설치하면 store라는 파일에 state를 보관하고 모든 컴포넌트들이 props 쓰지 않고 이를 가져다 쓸 수 있음

 

Redux와 Context API 비교

Context API

  • 비유: "가방 공유"
  • 여러 컴포넌트(학생들)가 하나의 가방(상태)을 공유하고 정보를 넣고 빼기 위해 사용
  • 각 컴포넌트(학생)는 필요할 때 가방(상태)을 열고 정보(데이터)를 확인하거나 변경 가능
  • 간단한 상태 공유에 좋고, 작은 규모의 앱에서 사용

Redux

  • 비유: "도서관 관리자"
  • 각 도서(상태)에는 제목과 내용(데이터)이 있음
  • 도서를 가져오거나 책장에 추가하려면 관리자(리듀서)에게 요청(액션)을 전송
  • Redux는 많은 컴포넌트(학생) 및 도서(상태)를 관리하는 데 유용하며, 큰 규모의 앱에서 사용할 때 유용

 

 

참고자료

React.js

https://sohyunsaurus.tistory.com/107

https://ahnanne.tistory.com/60

React

리액트가 널리 사용되는 이유는?

Higher Order Components(HOC)란?

React.js

리액트 18버전 https://dt101.tistory.com/20

 

 

 

728x90