02. 리액트 기본 설정 코드의 역할

김철준·2022년 1월 10일
0

REACT

목록 보기
3/33

🔍 코드분석

이번에는 npm create(init) react-app을 하였을 때 만들어지는 여러 리소스중 제일 중요한 파일인 index.js에 담겨져 있는 코드들을 분석하고자 한다.

📌 index.js

index.js의 코드를 들여다보면 다음과 같이 코드가 구성되어있다.
차례차례 살펴보자.

  1. ReactDOM.render()
  2. App
  3. ReactDOM
  4. React

☑️ 1. ReactDOM.render()

앞선 포스팅에서 살펴봤다시피 ReactDOM.render함수는 리액트요소를 DOM에 주입하여 렌더링하게 해주는 역할이라고 하였다.

container라는 DOM에 element를 주입하는 것이다.
첫번째 parameter : 페이지에 렌더링할 내용
두번째 parameter : 첫번째 parameter를 렌더링할 document 내부 요소 설정

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById("root")
);

id가 root인 div(DOM)에 이라는 컴포넌트를 주입하여 렌더링해주는 것이다.

☑️ 2. App

App은 컴포넌트이다. 위 코드를 살펴보면 id가 root인 div에 주입되는 요소는 App 컴포넌트가 주입된다. 즉, App을 페이지에 렌더링할 것이라는 코드인 것이다.

index.js에서 App.js를 import함.

하지만 App이라는 것은 코드 내에서 모듈로써 불러와지고 있다. 컴포넌트(App)는 파일(모듈)로써 분리되어 사용되어질 수 있다는 것이다.

컴포넌트는 파일로써 분리되어 사용될 수 있고 이를 import하여 사용하면 된다.

그렇다면 다음으로 App.js를 들여다보자.

App이라는 함수가 div요소를 리턴해주고 있다.
여기서 javascript에서 어떻게 html코드를 쓸 수 있는지에 관한 의문이 생긴다.

JSX

이 문법을 바로 리액트에서 사용하고 있는 JSX문법이라한다.

JSX코드는 브라우저에서 실행되기전에 코드가 번들링되는 과정에서 바벨을 사용하여 일반 자바스크립트 코드의 형태로 변환된다.
ECMA Script의 정식 문법이 아니며 개발의 편의를 위하여 만들어진 자바스크립트 확장문법이다.

즉, 위 코드는 html 코드처럼 생겼지만 html 코드를 쓴 것이 아닌 개발 편의를 위해 만들어진 자바스크립트 확장문법인 것이다.

다음 코드는 바벨을 이용하여 기존 자바스크립트 코드로 다음과 같이 변환된다.

createElement API는 javascript 코드를 작성할 때 많이 봤을 것이다.

  • createElement는 DOM 요소를 만들 때 사용하는 API이다.
  • 컴포넌트는 DOM요소를 반환한다.

위와 같이 코드를 사용해야한다면 불편하여 리액트를 사용하지 않을 지도 모른다.

JSX를 사용하면 html 코드를 작성하는 것처럼 편하게 UI를 생성하여 렌더링할 수 있다는 강점이 있다.

리액트의 강점:

  • Virtual DOM : 효율적인 렌더링을 하게 도와줌
  • JSX : 복잡한 문법을 간편화하여 편리하고 친숙하게 UI생성

다시 돌아와 , 이처럼 App함수는 JSX로 작성된 DOM요소를 반환한다.
그리고 export되어 모듈로써 내보내져 사용될 수 있게 된다.

다시 index.js로 돌아와 App함수(컴포넌트)를 사용하는 것을 살펴보자.

App이라는 함수를 모듈로써 불러와 쓰고 있지만 기존 함수를 사용할 때와 조금 다르다는 것을 알 수 있다.
기존 자바스크립트에서는 아래와 같이 쓰인다.

  App()

하지만 index.js에서는 아래와 같이 쓰이고 있다.

  <App/>

그렇다면 기존방식처럼 함수를 호출해본다면 어떠한 결과가 나올까?

  • index.js
  • App.js
  • 브라우저 결과

브라우저에는 Hello,React가 아닌 입력한 텍스트 그대로를 보여준다.
즉, ReactDOM.render()의 요소에 의도대로 DOM요소를 반환하기 위해서는 기존 함수 호출 방식이 아닌 리액트의 컴포넌트<>방식을 사용해야한다는 것을 알 수 있었다.

  • App.js
  • 브라우저 결과
  • 또한 ReactDOM.render()밖에서 컴포넌트(함수)를 사용한다면
    이는 렌더링되지않는다는 사실을 다시 한번 알 수 있었고 렌더링이 아닌 일반 객체 값으로 쓰인다는 것을 알 수 있었다.
  • 그리고 컴포넌트가 jsx문법이 아닌 다른 값을 반환하면 그 값 그대로의 텍스트를 렌더링 해준다는 것을 알 수 있었다.

☑️ 3. ReactDOM

ReactDOM은 "react-dom"모듈의 기능들을 사용할 수 있게 해준다.

This package serves as the entry point to the DOM and server renderers for React
참조: react-dom

DOM에 접근하여 DOM을 생성하고 변경하는 것이 주역할이다.
ReactDOM은 Virtual DOM을 사용하여 효율적으로 DOM을 관리하게 해준다.
즉, Virtual DOM과 직접적인 연관이 있는 패키지가 ReactDOM이다.

ReactDOM은 다음과 같은 메서드를 갖고 있다.

✒️ render()

이 메서드는 ReactDOM의 메서드 중 가장 중요하다.
이것은 DOM요소에 react component들을 주입하여 렌더링하게 해주는 역할을 한다.
또한 이는 DOM을 업데이트하는데 효율적인 방법을 제공하는 역할도 한다.

ReactDOM.render(element, container, [callback])

  • element : 이 변수는 JSX 표현식이나 리액트 엘리먼트가 들어갈 자리
  • container : 리액트 엘리먼트(컴포넌트)들이 들어갈 컨테이너
  • callback : 선택적인 변수이고 컴포넌트가 렌더링되거나 업데이트 될 때 불러지는 콜백함수이다.

render함수가 반환하는 것은 컴포넌트에 대한 참조이다.
render함수가 반환하는 것을 직접 쓰는 경우는 흔치 않다.

✒️ findDOMNode()

이 메서드는 컴포넌트의 DOM요소를 갖고 있는지 확인할 때 사용된다.
각 컴포넌트에 대한 DOM 참조는 attribute로 ref를 붙여 사용하면 되기 때문에 해당 메서드는 잘 사용하지 않는다.

  • ref: 컴포넌트에 대한 DOM 참조

    ReactDOM.findDOMNode(component)
    component : DOM요소를 찾을 컴포넌트

  • 주의 : 함수 컴포넌트에서는 사용할 수 없음.

✒️ hydrate()

이 메서드는 render 메서드와 비슷하지만 SSR(Server-Side-Rendering)기능을 사용할 수 있다.

ReactDOM.hydrate(element, container, callback)
* element : 이 변수는 JSX 표현식이나 리액트 엘리먼트가 들어갈 자리

  • container : 리액트 엘리먼트(컴포넌트)들이 들어갈 컨테이너
  • callback : 선택적인 변수이고 컴포넌트가 렌더링되거나 업데이트 될 때 불러지는 콜백함수이다.

기본적으로 render 메서드와 비슷하지만 서버에서 이미 마크업이 채워진 경우 hydrate(정적 => 동적)해주는 콜백함수만 써준다.

그냥 간단히 서버사이드렌더링할 때 쓰이는 메서드라 생각하자.

✒️ createPortal()

이 메서드는 원하는 위치에 컴포넌트를 위치시킬 수 있게 하는 기능을 한다.

ReactDOM.createPortal(child, container)
child: 위치시킬 컴포넌트
container : 컴포넌트를 지정할 위치

✒️ unmountComponentAtNode()

이 메서드는 마운트된 리액트 컴포넌트를 DOM에서 제거한다.

ReactDOM.unmountComponentAtNode(container)
return : true or false

DOM 요소를 제거할 때 사용된다.

ReactDOM 메서드 중 render함수가 가장 많이 쓰며 중요한 메서드임을 알아두자.

☑️ 4. React

React 모듈은 리액트의 여러가지 기능을 사용할 수 있는 메서드들을 모아두었다.
여러가지 React 메서드들이 있지만 추후에 공부할 개념들을 선행되야 이해가 갈 메서드들과 프로젝트를 진행하여야지 이해를 할 수 있는 메서드들이 많기 때문에 지금은 이러한 React메서드들이 있다는 것만 눈도장찍어놓고 가며 추후에 공부할 때 다시 언급해보자.

✒️ React.Component

React.Component 메서드는 클래스 컴포넌트를 정의할 때 상속해줄 리액트 기능을 담고 있다.
즉, React로 class 컴포넌트를 정의하기 위해서 React.Component를 상속받아야한다. 상속받음으로써 컴포넌트의 생명주기 메서드(componentDidMount,componentWillMount 등)들을 사용할 수 있다.

✒️ React.PureComponent

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

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

아직 shouldComponentUpdate()라는 생명주기메서드를 알아보지않았기때문에 눈으로만 짚고 넘어가자.
(생명주기 메서드는 클래스 컴포넌트를 공부할 때 알아볼 것이다.)

✒️ React.memo

React.memo는 고차 컴포넌트(Higher Order Component)이다.
컴포넌트가 동일한 props로 동일한 결과를 렌더링해낸다면, React.memo를 호출하고 결과를 메모이징(Memoizing)하도록 래핑하여 경우에 따라 성능 향상을 누릴 수 있다. 즉, React는 컴포넌트를 렌더링하지 않고 마지막으로 렌더링된 결과를 재사용한다.

이 또한 아직 props,state 또 이는 프로젝트를 구현하며 테스트해보는 것이 이해를 돕기 때문에 추후에 언급할 것이다.
지금은 이러한 React 메서드들이 있다는 것만 눈도장 찍어놓자.

✒️ React.createElement()

JSX를 사용하지 않고 리액트를 사용할 때 쓰인다. DOM 요소들을 생성하는 역할을 한다.

React.createElement(
type,
[props],
[...children]
)
type: html 태그 이름
prop : atrribute
children: 텍스트나 다른 dom요소

인자로 주어지는 타입에 따라 새로운 React 엘리먼트를 생성하여 반환한다. type 인자로는 태그 이름 문자열('div' 또는 'span' 등), React 컴포넌트 타입, 또는 React Fragment 타입 중 하나가 올 수 있다.

JSX코드로 작성된 코드는 React.createElement()형태로 변환된다.JSX를 사용할 경우 해당 메서드를 사용할 경우는 거의 없다.

✒️ React.cloneElement()

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

element를 기준으로 새로운 React 엘리먼트를 복사하고 반환한다. config는 key와 ref 그리고 모든 새로운 props를 포함한다. 새로운 엘리먼트에는 원본 엘리먼트가 가졌던 props가 새로운 props와 얕게 합쳐진 뒤 주어진다. 새로운 자식들은 기존의 자식들을 대체한다. config에 key와 ref가 없다면 원본 엘리먼트의 key와 ref는 그대로 유지된다.
즉, 복사하고 싶은 요소에 추가적인 변경을 하여 사용하고 싶을 때 사용하면 된다.

✒️React.isValidElement()

React.isValidElement(object)

객체가 React 요소인지 확인한다. true or false를 반환한다.

✒️React.children()

리액트 요소의 자식 요소들을 반환해준다.

✒️React.Fragment()

React.Fragment 컴포넌트를 사용하면 render() 메서드 안에서 추가적인 DOM 엘리먼트를 생성하지 않아도 여러 엘리먼트를 반환할 수 있다.

render() {
return (
<React.Fragment>
Some text.

  <h2>A heading</h2>
</React.Fragment>

);
}

축약형인 <></> 문법과 동일하다.

✒️React.createRef()

React.createRef는 React 엘리먼트에 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.lazy()

React.lazy()를 사용하면 동적으로 불러오는 컴포넌트를 정의할 수 있습니다. 그러면 번들의 크기를 줄이고, 초기 렌더링에서 사용되지 않는 컴포넌트를 불러오는 작업을 지연시킬 수 있습니다.

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

✒️ React.Suspense

React.Suspense를 사용하면 트리 상에 아직 렌더링이 준비되지 않은 컴포넌트가 있을 때 로딩 지시기(Loading indicator)를 나타낼 수 있다. 현재로서는 지연시켜서 불러오는 컴포넌트가 <React.Suspense>의 유일한 사용 사례이다.

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

function MyComponent() {
return (
  // Displays <Spinner> until OtherComponent loads
  <React.Suspense fallback={<Spinner />}>
    <div>
      <OtherComponent />
    </div>
  </React.Suspense>
);
}
  • lazy와 suspense는 code spliting과 관련이 깊은 추후에 공부할 때 심화하여 공부해보자.

☑️ 5. css,svg 기타파일 import

리액트에서는 웹팩을 사용하여 css파일,svg파일 등을 불러와서 사용할 수 있다. 이렇게 파일들을 불러오는 것은 웹팩의 로더라는 기능이 담당한다.

css-loader는 css파일을 불러올 수 있게 해주고, file-loader는 웹 폰트나 미디어 파일 등을 불러올 수 있게 해준다.
또한 babel-loader는 자바스크립트 파일을 불러오면서 최신 자바스크립트 문법들을 ES5문법으로 변환해주어 웹 브라우저에서 공통적으로 호환되게 해준다.(크로스 브라우징)

로더를 설치하여 사용하는 것은 웹팩에서 설정하여야하지만 npm create react-app이 이를 알아서 설정해준다.
추후에 커스터마이징하는 것은 따로 공부해봐야겠다.

📘 마치며..

이상으로 리액트 앱을 만들 때 필수적으로 필요한 라이브러리들의 역할,용도 또 어떤 메서드들이 있는지 구체적으로 알아봤다.
이전에는 이러한 부분들을 자세히 보지 않았지만 이렇게 학습함으로써 추후에 공부할 때 다른 것들을 이해할 수 있는 기반이 될 것 같다.

참조 : 리액트 공식 문서

profile
FE DEVELOPER

0개의 댓글