공식문서 API 참고서 React ~ ReactDOMServer

Genie·2022년 5월 15일
0
post-thumbnail
  • 컴포넌트
  1. React.Component

    React 컴포넌트 class를 정의하려면 React.Component를 상속받아야 한다.

    class Greeting extends React.Component {
    	render() {
    		return <h1>Hello, {this.props.name}</h1>
    	}
    }
  1. Reat.pureComponent

React.PureComponent는 React.Component와 비슷하다. React.Component는 shouldComponentUpdate()를 구현하지 않지만, React.PureComponent는 props와 state를 이용한 얕은 비교를 구현한다는 차이점만 존재한다.

React 컴포넌트의 render() 함수가 동일한 props와 state에 대하여 동일한 결과를 렌더링한다면, React.PureComponent를 사용하여 경우에 따라 성능 향상을 누릴 수 있다.

  • 고차 컴포넌트(HOC, Higher-Order Component)

리액트 컴포넌트를 인자로 받아 새로운 리액트 컴포넌트를 반환하는 함수

  • React.memo 고차 컴포넌트(Higher Order Component)이다. 컴포넌트의 리렌더링을 방지할 때는 shouldComponentUpdate라는 라이프사이클 메서드을 사용하면 된다. 함수형 컴포넌트에서는 그 대신 React.memo 함수를 사용한다. 컴포넌트의 props가 바뀌지 않았다면, 리렌더링 하지 않도록 설정하여 함수형 컴포넌트의 리렌더링 성능을 최적화해 줄 수 있다. (마지막 렌더링 결과를 재사용)
    // todo, onRemove, onToggle이 바뀌지 않으면 리렌더링 하지 않는다.
    const TodoListItem = ({ todo, onRemove, onToggle }) => {};
    
    export default React.memo(TodoListItem);
    ⇒ 렌더링을 방지하기 위함이 아닌, 성능 최적화를 위해 사용하자!
  • JSX없이 React를 사용할 경우 사용하는 메서드
  1. createElement()

    React.createElement(type, [props], [...children]);

    type: 태그 이름 문자열 ex) div, span, React 컴포넌트, React Fragement

    JSX로 작성된 코드는 React.createElement()를 사용하는 형태로 변환된다.

  1. createFactory(type)

type: 태그 이름 문자열 ex) div, span, React 컴포넌트, React Fragement

이 함수는 레거시 기능으로 간주되며, 대신 JSX를 사용하거나 React.createElement() 사용을 권장한다.

  • React에서 엘리먼트를 조작하는 API
  1. cloneElement(element, [props], [...children])

    element를 기준으로 새로운 React 엘리먼트를 복사하고 반환한다.

  2. React.isValidElement(object)

    객체가 React 엘리먼트인지 확인한다. ⇒ true or false를 반환

  3. React.Children

    this.props.children을 다루는 유틸함수를 제공한다.

    ex) React.Children.map, React.Children.forEach, React.Children.count, React.Children.only, React.Children.toArray

  • React.Fragment(<></>)

React에서 래퍼 없이 여러 엘리먼트를 렌더링할 수 있는 컴포넌트를 제공한다.

  • Refs

컴포넌트에 접근할 수 있는 특수한 어트리뷰트 ref

  1. React.createRef()

    React 엘리먼트에 ref 어트리뷰트를 붙일 수 있는 ref를 생성한다.

this.inputRef = React.createRef();
  1. React.forwardRef()

전달 받은 ref 어트리뷰트를 하부 트리 내의 다른 컴포넌트로 전달하는 React 컴포넌트를 생성한다.

React.forwardRef는 렌더링에 사용될 함수를 인자로 받을 수 있다. React는 이 함수를 두 개의 인자 props와 ref를 사용하여 호출하고, 이 함수는 React 노드를 반환한다.

const FancyButton = React.forwardRef((props, ref) => (
	<button ref={ref} className="FancyButton">
		{props.children}
	</button>
));

const ref = React.createRef();
<FancyButton ref={ref}>Click me!</FancyButton>

⇒ ref.current는 <button> DOM 엘리먼트를 가리키게 된다.

  • Refs를 남용하면 안되는 이유

React 팀은 "선언적으로 수행 할 수 있는 모든 작업에 refs를 사용하지 마십시오."라고 말했다.

그들은 “Refs를 남용하지 말라”는 제목을 강조했다.

그들은 "가능하면 DOM 노드를 노출하지 않는 것이 좋지만 유용한 탈출 해치가 될 수 있습니다." 라고 다시 강조했다.

  • 코드 스플리팅(Code Splitting, 코드 분할)

웹 서비스가 배포 되어질 때 모든 코드들은 하나의 번들로 번들링 된다. 서비스가 비교적 가벼운 편이라면 큰 문제가 없겠지만, 프로젝트의 규모가 커지고 전달 해야하는 데이터의 양이 커지게 되면 성능적 문제가 발생하게 된다. 그래서 개발자는 위와 같은 불편함을 느끼지 못하도록 유저가 당장 필요한 정보에 우선순위를 두어 순서대로 로딩하는 방법이 있다. 앱의 정보가 아직 로딩중이라도 유저에게는 티를 내지 않는 방법이다.

즉, 번들이 커지는 것을 방지하기 위해 번들을 분할하는 것이다. 코드 스플리팅은 런타임에 여러 번들을 동적으로 만들고 불러오는 것으로 Webpack, Rollup, Browserify 같은 번들러가 지원하는 기능이다.

코드 스플리팅은 앱을 지연로딩(lazy loading) 할 수 있게 도와주고, 획기적인 성능 향상을 하게된다. 앱의 코드 양을 줄이지 않고도 필요하지 않은 코드를 불러오지 않게 하며, 초기화 로딩에 필요한 비용을 줄여준다.

앱에 코드 스플리팅을 도입하는 가장 좋은 방법은 dynamic import()를 사용하는 방법이다.

  • suspense

suspense를 사용하면 컴포넌트가 렌더링하기 전에 다른 작업이 먼저 이루지도록 대기한다.

  1. React.lazy

    동적으로 불러오는 컴포넌트를 정의할 수 있다.

    그러면 번들의 크기를 줄이고, 초기 렌더링에서 사용되지 않는 컴포넌트를 불러오는 작업을 지연시킬 수 있다.

    React.lazy는 코드 분할(코드 스플리팅)을 하게 해준다. 코드 분할은 앱을 지연 로딩하게 도와주고, 사용자들에게 획기적인 성능 향상을 하게 해준다. 앱의 코드 양을 줄이지 않고도 사용자가 필요하지 않은 코드를 불러오지 않게 하며 앱의 초기화 로딩에 필요한 비용을 줄여준다.

    React.lazy는 아직 SSR을 하지 못해서 SSR을 위해서는 Loadable Components를 추천한다.

  1. React.Suspense

React.lazy로 불러진 컴포넌트는 Suspense 컴포넌트 하위에서 렌더링되어야 하며, Suspense는 lazy 컴포넌트가 로드되는 동안 로딩화면과 같은 예비 컨텐츠를 보여줄 수 있다.

import React, { lazy, Suspense } from 'react';

const OtherComponent = lazy(() => import('./OtherComponent'));

function MyComponent() {
	return (
		<div>
			<Suspense fallback={<Spinner />}>
				<OtherComponent />
			</Suspense>
		</div>
	);
}
  • Hooks

Hooks는 React 16.8에 새로 추가되었다. Hooks를 사용하면 class를 사용하지 않아도 함수형 컴포넌트에서 상태관리 할 수 있고, 기존에 함수형 컴포넌트에서 할 수 없었던 다양한 작업을 할 수 있게 해준다.

React 공식문서에 클래스 컴포넌트는 코드 재사용성과 코드 구성을 어렵게 만들 뿐만 아니라, React를 배우는데 큰 진입장벽이라고 말한다. 이러한 배경에서 훅이 등장하게 되었다.

  • 클래스형 컴포넌트에서는 상태를 가질수 있는데, 함수형 컴포넌트에서는 상태를 가질 수 없는 이유?

클래스는 인스턴스를 한 번만 만들고, 그 인스턴스를 가지고 라이프사이클을 돌리니까 인스턴스 안에서 만들어 놓은 상태는 유지된다. 함수는 업데이트 될 때 마다 모든 것을 초기화한다. 따라서 상태를 가질 수 없었지만, React hooks이 등장한 이후로 상태를 관리할 수 있게 되었다.

  • 컴포넌트 라이프사이클(생명 주기) 메서드 9가지

컴포넌트의 수명은 페이지에 렌더링되기 전인 준비과정에서 시작하여 페이지에서 사라질 때 끝난다.

라이프사이클 메서드는 클래스형 컴포넌트에서만 사용할 수 있다. 라이프 사이클 메서드를 사용하면 특정 시점에 코드가 실행되도록 설정할 수 있다.

Will: 어떤 작업을 작동하기 전

Did: 어떤 작업을 작동한 후


  • 마운트 시 호출되는 메서드

마운트: DOM이 생성되고 웹 브라우저 상에 나타나는 것

constructor: 컴포넌트를 새로 만들 때마다 호출되는 클래스 생성자 메서드

getDerivedStateFromProps: props에 있는 값을 state에 넣을 때 사용하는 메서드

render: 우리가 준비한 UI를 렌더링 하는 메서드

componentDidMount: 컴포넌트가 웹 브라우저 상에 나타난 후 호출하는 메서드

  • 컴포넌트가 업데이트 되는 경우
  1. props가 바뀔 때
  2. state가 바뀔 때
  3. 부모 컴포넌트가 리렌더링될 때
  4. this.forceUpdate로 강제로 렌더링을 트리거할 때
  • 업데이트 시 호출되는 메서드

getDerivedStateFromProps: 마운트 과정에서도 호출되며, 업데이트가 시작하기 전에도 호출된다. props의 변화에 따라 state 값에도 변화를 주고 싶을 때 사용한다.

shouldComponentUpdate: 컴포넌트의 리렌더링 여부를 결정하는 메서드이다. 이 메서드는 true 또는 false 값을 반환해야 하며 true를 반환하면 다음 라이프사이클 메서드를 계속 실행하고, false를 반환하면 작업을 중지한다. 즉, 컴포넌트가 리렌더링 되지 않는다. 만약 특정 함수에서 this.forceUpdate() 함수를 호출한다면 이 과정을 생략하고 바로 render 함수를 호출한다.

render: 컴포넌트를 리렌더링한다.

getSnapshotBeforeUpdate: 컴포넌트 변화를 DOM에 반영하기 바로 직전에 호출하는 메서드

componentDidUpdate: 컴포넌트 업데이트 작업이 끝난 후 호출하는 메서드

  • 언마운트 시 호출되는 메서드

언마운트: 컴포넌트를 DOM에서 제거하는 것

componentWillUnmount: 컴포넌트가 웹 브라우저 상에서 사라지기 전에 호출하는 메서드

  • 오류 처리

자식 컴포넌트를 렌더링하거나, 자식 컴포넌트가 생명주기 메서드를 호출하거나, 또는 자식 컴포넌트가 생성자 메서드를 호출하는 과정에서 오류가 발생했을 때 호출된다.

getDerivedStateFromError()

componentDidCatch()

  • class 프로퍼티
  1. defaultProps: props의 기본값을 설정할 수 있다.
  2. displayName
  • 인스턴스 프로퍼티
  1. props
  2. state
  • render 메서드(O)

컴포넌트의 모양새를 정의한다.

라이프사이클 메서드 중 유일한 필수 메서드이다.

render() 함수는 순수해야 한다. 즉, 컴포넌트의 state를 변경하지 않고 호출될 때마다 동일한 결과를 반환해야하며, 브라우저와 직접적으로 상호작용을 하지 않는다.

브라우저와 상호작용하는 작업이 필요하다면, 해당 작업은 componentDidMount()나 다른 생명주기 메서드 내에서 수행해야 한다.

  • constructor 메서드(O)
constructor(props) {
	super(props);
	this.state = { counter: 0 };
	this.handleClick = this.handleClick.bind(this);
}

컴포넌트의 생성자 메서드로 컴포넌트를 만들 때 처음으로 실행된다. 이 메서드에서는 초기 state를 정할 수 있다.

메서드를 바인딩하거나 state를 초기화하는 작업이 없다면, 해당 React 컴포넌트에는 생성자를 구현하지 않아도 된다.

constructor는 this.state를 할당할 수 있는 유일한 곳이다. 그 외의 메서드에서는 this.setState()를 사용해야 한다.

  • getDerivedStateFromProps 메서드

props로 받아온 값을 state에 동기화시키는 용도로 사용하며, 컴포넌트가 마운트 될 때와 업데이트될 때 호출된다.

static getDerivedStateFromProps(nextProps, prevState) { ... }
  • componentDidMount 메서드(O)

컴포넌트가 마운트된 직후에 호출된다.

즉, 컴포넌트를 만들고, 첫 렌더링을 다 마친 후 실행한다. 이 안에서 JS 라이브러리 또는 프레임워크의 함수를 호출하거나 이벤트 등록, setTimeout, setInterval, 네트워크 요청 같은 비동기 작업을 처리하면 된다.

  • shouldComponentUpdate 메서드

props 또는 state를 변경했을 때, 리렌더링을 시작할지 여부를 지정하는 메서드이다. 이 메서드는 true 또는 false 값을 반환해야 한다. 컴포넌트를 만들 때 이 메서드를 따로 생성하지 않으면 기본적으로 언제나 true 값을 반환한다. false를 반환한다면 업데이트 과정은 여기서 중지된다.

프로젝트 성능을 최적화할 때, 상황에 맞는 알고리즘을 작성하여 리렌더링을 방지할 때는 false 값을 반환하게 한다.

shouldComponentUpdate(nextProps, nextState) { ... }
  • getSnapshotBeforeUpdate 메서드

render에서 만들어진 결과물이 브라우저에 실제로 반영되기 직전에 호출된다. 이 메서드에서 반환하는 값은 componentDidUpdate에서 세 번째 파라미터인 snapshot 값으로 전달받을 수 있는데, 주로 업데이트하기 직전의 값을 참조할 일이 있을 때 활용된다. (ex) 스크롤바 위치 유지)

getSnapshotBeforeUpdate(prevProps, prevState) { ... }
  • componentDidUpdate 메서드(O)

리렌더링을 완료한 후에 실행된다. 업데이트가 끝난 직후이므로 DOM 관련처리를 해도 무방하다. prevProps 또는 prevState를 사용하여 이전 데이터에 접근할 수 있다. 또 getSnapshotBeforeUpdate에서 반환한 값이 있다면 여기서 snapshot 값을 전달받을 수 있다.

componentDidUpdate(prevProps, prevState, snapshot) { ... }
  • componentWillUnmount 메서드(O)

컴포넌트를 DOM에서 제거할 때 실행한다. componentDidMount에서 등록한 이벤트, 타이머, 직접 생성한 DOM이 있다면 여기서 제거 작업을 해야 한다.

  • componentDidCatch 메서드

componentDidCatch는 리액트 v16에서 새롭게 도입되었으며, 컴포넌트 렌더링 도중에 에러가 발생했을 때 애플리케이션이 먹통이 되지 않고 오류 UI를 보여 줄 수 있게 해준다.

// error: 어떤 에러가 발생했는지
// info: 어디에 있는 코드에서 에러가 발생했는지에 대한 정보
componentDidCatch(error, info) {
	this.setState({
		error: true
	});
	console.log({ error, info });
}
  • Error Boundary

Error Boundary는 자식 컴포넌트 트리 내의 자바스크립트 오류를 감지하고, 해당 오류를 기록하며, 충돌이 발생한 컴포넌트 트리를 대신하여 대체 UI를 표시하는 React 컴포넌트이다.

즉, Error Boundary는 트리 내에서 자신보다 하위에 존재하는 컴포넌트에 대한 오류만 감지해낸다. 자기 자신에 대한 오류를 감지할 수 없다.

Error Boundary의 하위 트리에 존재하는 렌더링 과정, 생명주기 메서드, 모든 생성자에 대하여 오류를 감지해낸다.

클래스 컴포넌트에 getDerivedStateFromError() 또는 componentDidCatch()를 정의할 경우 해당 컴포넌트는 Error boundary가 된다.

  • setState 메서드

컴포넌트 state 변경 사항을 대기열에 집어 넣고, React에게 해당 컴포넌트와 그 자식들이 갱신된 state를 사용하여 다시 렌더링되어야 한다고 알린다.

setState(updater, [callback]);

setState()는 컴포넌트를 항상 즉각적으로 갱신하지는 않는다. 만약 이로 인한 문제를 해결하고 싶은경우 componentDidUpdate 또는 setState의 콜백을 사용하면 된다.

this.setState((state, props) => {
	return { counter: state.counter + props.counter
})
  • ReactDOM API
  1. render 메서드
ReactDOM.render(element, container[, callback]);

React 엘리먼트를 container DOM에 렌더링하고 컴포넌트에 대한 참조를 반환한다.

추가적인 콜백이 제공된다면 컴포넌트가 렌더링되거나 업데이트된 후에 실행된다.

  1. hydrate 메서드
ReactDOM.hydrate(element, container[, callback]);

SSR을 해서 이미 마크업이 채워져있는 경우 굳이 render 메서드를 사용할 필요가 없다. SSR을 하는 경우에는 hydrate로 콜백만 붙여야한다.

그래서 SSR을 하는 경우에 ReactDOM의 render 메소드가 아니라 hydrate 메소드를 사용해야 한다.

서버에서 내려준 HTML로 렌더링 된 화면은 그냥 단순히 그림일 뿐이다. 리액트가 관리되지 않는 화면이다. SSR을 하더라도 컴포넌트를 리액트가 관리하게 하기 위해서는 hydration은 꼭 필요한 작업이다.

참고) https://simsimjae.tistory.com/389

  1. unmountComponentAtNode()
ReactDOM.unmountComponentAtNode(container);

마운트된 React 컴포넌트를 DOM에서 제거하고 컴포넌트의 이벤트 핸들러와 state를 정리한다.

  1. findDOMNode()

이 메서드는 StrictMode에서 권장되지 않는다.

매개변수로 전달받은 컴포넌트가 DOM 내부에 마운트되었다면 컴포넌트에 해당하는 네이티브 브라우저의 DOM 엘리먼트를 반환한다.

  1. createPortal()
React.createPortal(child, container);

portal을 생성한다. Portal은 DOM 컴포넌트 구조의 외부에 존재하는 DOM 노드에 자식을 렌더링하는 방법을 제공한다.

profile
front-end engineer

0개의 댓글