React 공식 문서 해석하며 공부하기 : React Top-Level API

배지로·2021년 8월 31일
0
post-thumbnail

해석하며 공부하는 것을 목적으로 하기 때문에 다수의 의역, 오역이 있음을 미리 밝힙니다.
원본 : https://reactjs.org/docs/react-api.html
*cloneElement()에 대한 부분이 특히 매끄럽지 않습니다. 주의해서 읽어주세요

리액트 최상위 레벨 API

React는 리액트 라이브러리의 시작점입니다. <script>태그에서 리액트를 불러온다면, 최상위 레벨 API들은 React전역에서 사용할 수 있습니다. npm을 통해 ES6을 사용하고 있다면, import React from 'react'를 작성하면 됩니다. npm을 통해 ES5를 사용하고 있다면, var React=require('react')를 작성하면 됩니다.


개요

컴포넌트

리액트 컴포넌트는 UI를 독립적으로, 재사용이 가능하게 분할하도록 하고, 각 부분을 분리하여 생각할 수 있게 도와줍니다. 리액트 컴포넌트는 React.ComponentReact.PureComponent로 하위 분류됩니다.

  • React.Component
  • React.PureComponent

ES6을 사용하고 있지 않다면,create-react-class 모듈을 사용하십시오. ES6 없이 리액트 사용하기 문서에서 더 많은 정보를 얻을 수 있습니다.

리액트 컴포넌트는 래핑될 수 있는 함수에 의해서 정의되는 것도 가능합니다.

  • React.memo

리액트 엘리먼트 만들기

UI를 묘사하는 데는 JSX를 사용하는 것이 권장됩니다. 각 JSX 엘리먼트는 React.createElement()를 호출하기 위한 문법적 설탕에 불과합니다. JSX를 사용하고 있다면 아래의 메소드를 직접 호출할 일은 보통 없을 것입니다.

  • createElement()
  • createFactory()

JSX없이 리액트 사용하기 문서에서 더 많은 정보를 얻을 수 있습니다.

엘리먼트 변환하기

React는 엘리먼트 조작을 위한 여러가지 API를 제공합니다.

  • cloneElement()
  • isValidElement()
  • React.Children

Fragments

React는 또한 wrapper없이 여러 엘리먼트들을 렌더링하기 위한 컴포넌트를 제공합니다.

  • React.Fragment

Refs

  • React.createRef
  • React.forwardRef

Suspense

Suspense는 렌더링하기 전에 컴포넌트가 무언가를 "기다리는" 것을 가능하게 합니다. 현재 Suspense에는 오직 하나의 사용 예시가 있습니다 : React.lazy를 이용하여 동적으로 컴포넌트 로딩하기 추후에 Suspense는 데이터 불러오기와 다른 사용 예시들도 지원될 것입니다.

  • React.lazy
  • React.Suspense

Hooks

Hooks는 리액트 16.8 버전에 새롭게 추가되었습니다. class를 사용하지 않고도 state나 다른 리액트 도구들을 사용할 수 있습니다. Hooks만을 다루는 문서와 API 문서가 존재합니다 :

  • Basic Hooks
    - useState
    - useEffect
    - useContext
  • Additional Hooks
    - useRender
    - useCallback
    - useRef
    - useInperativeHandle
    - useLayoutEffect
    - useDebugValue


참조

React.Component

React.Component는 ES6 클래스를 사용할 때 리액트 컴포넌트에 가장 기본이 되는 클래스입니다 :

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

React.Component API Reference에서 기본 React.Component 클래스 관련된 메소드와 프로퍼티 리스트를 확인하실 수 있습니다.


React.PureComponent

React.PureComponentReact.Component와 아주 비슷합니다. React.ComponentShoulComponentUpdate()를 구현하지 않았고, React.PureComponent는 prop와 state를 얕은 비교를 통해 비교하는 ShoulComponentUpdate()를 구현했다는 점에서 차이가 있습니다.

리액트 컴포넌트의 render()함수가 동일한 props와 state에 대해 동일한 결과를 받는다면, 성능 향상을 위해 React.PureComponent를 사용하는 것이 좋습니다.

참고
React.PureComponent의 shouldComponentUpdate()는 객체를 얕게만 비교합니다. 이 컴포넌트가 복잡한 데이터 구조를 가졌다면, 깊은 차이를 가짐에도 불구하고 차이가 없다고 판단할 수 있습니다. props와 state의 구조가 간단하다고 예상될 때만 PureComponent를 사용하거나 깊은 데이터 구조가 변화되는 것을 알 때 forceUpdate()를 사용하세요. 또는, 중첩된 데이터의 빠른 비교를 가능하게 하기 위해서 불변의 객체를 사용하는 것을 고려해보는 것도 좋습니다.
더 나아가, React.PureComponent의 shouldComponentUpdate()는 전체 컴포넌트의 하위트리의 prop 업데이트를 건너뜁니다. 모든 자식 컴포넌트가 "pure"인지 확인해주세요.


React.memo

const MyComponent = React.memo(function
MyComponent(props){
  /*prop을 사용해서 렌더링*/
});

React.memo는 고차 컴포넌트(higher order component)입니다.

컴포넌트다 같은 props에 의해서 같은 결과를 렌더링한다면, 결과를 기억함으로서 높은 성능을 기대하는 Recat.memo 호출로 컴포넌트를 감쌀 수 있습니다. 이것은 리액트는 컴포넌트 렌더링을 건너뛸 수 있고, 마지막으로 렌더링된 결과를 재사용할 수 있다는 뜻입니다.

React.memo는 prop 변화만 체크합니다. React.memo로 감싼 함수 컴포넌트가 useState,useReducer, 또는 useContext 훅을 사용하여 구현되었다면, 다른 컴포넌트와 마찬가지로 state나 context가 변화할 때 다시 렌더링될 것입니다.

기본적으로 prop 객체 안의 복잡한 객체들은 오로지 얕은 비교만 합니다. 비교 방법을 제어하고 싶다면, 두번째 매개변수에 커스텀 비교 함수를 넣으면 됩니다.

function MyComponent(props){
  /*props을 이용하여 렌더링*/
}

function areEqual(prevProps, nextProps){
  /* 렌더링할 nextProps를 전달한 것과 prevProps를 전달한 
  결과가 같다면 true를 반환하고, 아니면 false를 반환한다*/
}

export default React.memo(MyComponent, areEqual);

이 메소드(areEqual)는 성능 최적화를 위해서만 존재합니다. 렌더링을 "방지하기" 위하여 사용하지 마세요. 버그를 유발할 수 있습니다.

참고
shouldComponentUpdate()메소드가 클래스 컴포넌트에 쓰이는 것과 다르게, areEqaul함수는 props이 동일하면 true를 반환하고, 동일하지 않으면 false를 반환합니다. 이것은 shoulComponentUpdate와 정반대입니다.


createElement()

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

인자로 주어지는 타입에 따라 새로운 리액트 엘리먼트를 만들고 반환합니다. type 매개변수는 태그 이름 문자열('div'나 'span'과 같은)이거나 리액트 컴포넌트 형식(class나 function)이거나 리액트 fragment 형식입니다.

JSX로 작성된 코드는 React.createElement()로 변환됩니다. JSX를 사용하면 React.createElement()를 직접 불러오지 않아도 됩니다. 더 많은 정보는 React without JSX를 확인하세요.


cloneElement()

React.cloneElement(
  element,
  [config],
  [...children]
);

element를 기준으로 새로운 리액트 앨리먼트를 복사하고 반환합니다. config는 모든 새로운 props, key, ref를 포함합니다. 결과적으로 만들어지는 엘리먼트는 기존 엘리먼트의 props와 새로운 props가 얕게 병합된 뒤 주어집니다. 새로운 자식 엘리먼트는 기존 엘리먼트를 대체합니다.keyrefconfig에 없으면 기존 엘리먼트의 keyref는 보존됩니다.

React.cloneElement()는 아래와 거의 동일합니다 :

<element.type {...element.props} {...props}>{children}</element.type>

그러나 React.cloneElement()refs을 보존하기도 합니다.ref가 자식 컴포넌트에 있다면, 그것을 자식 컴포넌트보다 상위 컴포넌트들로 가져올 수 없습니다.ref가 붙어있는 새로운 엘리먼트를 받게 될 것입니다. 새로운 refkey는 오래된 것들을 대체합니다.

이 API는 앞으로 사라지게 될 React.addons.cloneWithProps()를 대체하기 위해 소개되었습니다.


createFactory()

React.createFactory(type)

주어진 형식의 리액트 엘리먼트들을 만드는 함수를 반환합니다. React.createElement()처럼, type 매개변수는 'div'나 'span'과 같은 태그 이름 문자열이 될 수도 있고, 클래스나 함수와 같은 리액트 컴포넌트 타입이 될 수도 있고, 리액트 fragment 타입이 될 수도 있습니다.

이 헬퍼 함수는 레거시로 간주되며, JSX나 React.createElement()를 직접 사용하는 것을 권장합니다.

JSX를 사용한다면 대부분 React.createElement()를 불러오지 않습니다. 더 많은 정보는 React without JSX를 확인하세요.


isValidElement()

React.isValidElement(object)

object가 리액트 엘리먼트인지 확인합니다. true 또는 false를 반환합니다.


React.Children

React.Childrenthis.props.children이라는 불투명 자료구조를 다룰 수 있는 유틸리티들을 제공합니다.

React.Children.map

React.Children.map(children, function[(thisArg)])

children 내부의 포함된 모든 자식들에 대해 thisthisArg를 세팅한 함수를 불러옵니다. children이 배열이라면 배열을 순회하면서 배열의 각 원소에 의해 함수가 호출될 것입니다. 배열의 원소들이 null이나 undefined라면, 이 메소드는 배열보다는 null이나 undefined를 반환할 것입니다.

참고
만약 childrenFragment라면, 단일 원소로 취급되어서 순회하지 않을 것입니다.

React.Children.forEach

React.Children.forEach(children, function[(thisArg)])

React.Children.map()과 비슷하지만 배열을 반환하지는 않습니다.

React.Children.count

React.Children.count(children)

children안의 컴포넌트의 총 개수를 반환합니다. 이것은 map이나 forEach로부터 전달된 콜백함수가 불려지는 횟수와 같습니다.

React.Children.only

React.Children.only(children)

children이 하나의 자식(리액트 앨리먼트)만을 가지고 있음을 확인하고, 그것을 반환합니다. 그렇지 않으면 오류를 발생시킵니다.

참고:
React.Children.only()React.Children.map()의 반환 값을 받아들이지 않습니다. 반환값이 리액트 앨리먼트가 아니고 배열이기 때문입니다.

React.Children.toArray

React.Children.toArray(children)

불투명 자료 구조인 children을 각 자식에 할당된 키의 배열로서 반환합니다. render 메소드에서 자식들의 집합을 조작하는데 유용하며, 특히 this.props.children을 하위 컴포넌트에 전달하기 전에 다시 정렬하거나 일부만 잘라내고 싶을 때 유용합니다.

참고:
React.Children.toArray()는 중첩된 배열의 의미를 보존하기 위해서 키를 바꿉니다. 즉, 각 엘리먼트의 키는 해당 키가 포함된 입력 배열로 범위가 지정되게 하기 위하여 toArray는 반환된 배열에서의 각 키를 앞에 붙입니다.


React.Fragment

React.Fragment 컴포넌트는 render() 메소드에서 추가적인 DOM 엘리먼트를 만들지 않고 여러 개의 엘리먼트들을 반환할 수 있도록 합니다.

render(){
  return(
    <React.Fragment>
      Some.text.
      <h2>A heading</h2>
    </React.Fragment>
  );
}

<React.Fragment>대신에 <></>문법을 사용할 수도 있습니다. 더 많은 정보는 React v16.2.0: Fragment을 위한 개선된 설명서를 참조하세요.

React.createRef

React.createRef는 ref 속성을 통해서 리액트 엘리먼트에 추가될 수 있는 ref를 만듭니다.

class MyComponent extends React.Component{
  constructor(props){
    super(props);
    
    this.inputRef=React.createRef();
  }
  
  render(){
    return <input type="text" ref={this.inputRef} />
  }
  
  componentDidMount(){
    this.inputRef.current.focus();
  }
}

React.forwardRef

React.forwardRef는 전달받은 ref 속성을 하부 트리 내의 다른 컴포넌트로 전달하는 리액트 컴포넌트를 만듭니다. 이 기술은 일반적이지 않지만 두 가지 시나리오 상에서는 특히 유용합니다 :

React.forwardRef 매개변수로 렌더링 함수를 받아들입니다. 리액트는 props와 ref를 모두 매개변수로 받아들이는 함수를 호출합니다. 이 함수는 리액트 노드를 반환합니다.

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

//DOM으로부터 직접 ref를 받는다
const ref=React.createRef();
<FancyButton ref={ref}>Click me!</FancyButton>

위의 예시에서 리액트는 <FancyButton ref={ref}> 엘리먼트에 주어진 refReact.forward 호출 시 렌더링 함수의 두번째 인자로 전달합니다. 이러한 렌더링 함수는 ref<button ref={ref}>엘리먼트로 전달합니다.

결과적으로, 리액트가 ref를 사용함으로서 ref.current<button> DOM 엘리먼트 인스턴스를 직접 가리키게 됩니다.

더 많은 정보는 ref 전달하기 문서에서 확인하세요.

React.lazy

React.lazy()는 동적으로 불러오는 컴포넌트를 정의할 수 있습니다. 이것은 초기 렌더링에 사용되지 않는 컴포넌트를 불러오는 것이 지연되도록 하는 번들의 크기를 줄일 수 있습니다.

Code Splitting문서에서 React.lazy()를 어떻게 사용하는지 배울 수 있으며, 더 자세히 쓸 수 있는 방법에 대해서는 이 문서를 참고해보세요.

//이 컴포넌트는 동적으로 불러옵니다.
const SomeComponent=React.lazy(()=> import('./SomeComponent'));

lazy 컴포넌트를 렌더링하려면 렌더링 트리의 상위에 <React.Suspense> 컴포넌트가 요구됩니다. 로딩 지시자를 불러오는 방법입니다.

참고
동적 import를 통해 React.lazy를 사용하는 것은 JS 환경이 Propmise를 지원해야합니다. IE11 이하에서는 polyfill이 필요합니다.

React.Suspense

React.Suspense는 트리 상에 렌더링이 준비되지 않은 컴포넌트가 있을 때 로딩 지시기를 명시할 수 있게 도와줍니다. 오늘날, lazy 로딩 컴포넌트가 <React.Suspense> 에 의해 지원되는 유일한 사용 예시입니다:

//이 컴포넌트는 동적으로 불러옵니다.
const OtherComponent=React.lazy(()=>import('./OtherComponent'));
import('./OtherComponent');

function MyComponent(){
  return(
    //OtherComponent가 로딩될 때까지 <Spinner>를 보여줍니다.
    <React.Suspense fallback={<Spinner/>}>
      <div>
        <OtherComponent/>
      </div>
    </React.Suspense>
  );
}

이것은 code splitting 지원 가이드입니다. lazy 컴포넌트는 Suspense트리의 깊숙히 위치할 수 있다는 것을 주의하세요. 즉, Suspense가 모든 것을 감쌀 필요는 없다는 것입니다. 가장 좋은 방법은 로딩 지시자를 보고 싶은 곳에 <Suspense>를 위치시키는 것이지만, Code Splitting을 하고 싶은 어느 곳이든 lazy()를 위치시킬 수 있습니다.

현재는 지원하고 있지 않지만, 추후에 데이터 불러오기와 같은 많은 경우를 다루는 Suspense를 지원할 예정입니다. 이것에 대한 정보는 로드맵 문서를 참조하세요.

참고:
React.lazy()<React.Suspense>는 아직 ReactDOMServer에 의해 지원되지 않습니다. 이러한 제한 사항은 추후 해결될 예정입니다.

                           
profile
웹 프론트엔드 새싹🌱

0개의 댓글