Why?

이번에 회사에서React를 도입하게 되었다. React를 학습하면서 배운 개념과 내용을 정리하기 위해 글을 작성하게되었다.

React를 배우기 전 알아두어야 할 몇가지 개념

Rendering?

  • 서버로부터 HTML 파일을 받아 브라우저에 뿌려주는 과정이다.

SPA?

  • SPA(Single Page Application)는 단일 페이지로 구성되어 있으며, SPA에서는 애플리케이션에 필요한 모든 리소스를 한 번에 로드한다. 그리고 뷰 렌더링은 모두 브라우저에서 담당하며 변경은 자바스크립트로 처리한다. (최초 모든 리소스를 다 로드하면 오버헤드가 발생하기에 Code Spliting 을 통해 라우트 별로 파일을 쪼개서 해소하기도 한다.)

    (기존 방식 - 링크를 통해 새로운 페이지를 서버에 요청한다. 이에따라 사용자와의 인터렉션이 많아지고, 새로운 페이지를 요청할 때 변경이 없는 부분을 포함해서 전체 페이지를 다시 로드한다.)

DOM과 Virtual DOM?

  • DOM : 문서 객체 모델(The Document Object Model, 이하 DOM) 은 HTML, XML 문서의 프로그래밍 interface이다. 단순 텍스트로 구성된 HTML 문서의 내용과 구조가 객체 모델로 변환되어 다양한 프로그램에서 사용될 수 있다는 점이며, 노드 트리 구조로 표현한다.

  • Virtual DOM : DOM의 가변운 복사 본이며, 인메모리에 존재하기 떄문에 실제 렌더링 되지 않는다. 데이터가 업데이트 되면 전체 UI를 Virtual DOM에 리렌더링하고, 이전 Virtual DOM에 있던 내용과 현재의 내용을 비교해서 바뀐 부분만 실제 DOM적용하는 방식으로 진행된다.

Component(props, state)

  • UI를 구성하는 개별적인 뷰 단위React로 개발을 한다는 것은 마치 블럭을 조립해 성을 만드는 것과 같다. 앱의 다른 부분, 또는 다른 앱에서 쉽게 재사용이 가능하다. (페북 -> 유지 가능한 앱)

  • props : props는 컴포넌트에서 사용 할 데이터 중 변동되지 않는 데이터를 다룰 때 사용된다.parent 컴포넌트에서 child 컴포넌트로 데이터를 전할 때, props가 사용된다.

  • state : 컴포넌트에서 유동적인 데이터를 다룰 때, state 를 사용한다. App.js를 사용하고 있는index.js에서는 state가 어떤 역할을 하는지 알 수 없다. 알 필요도 없다. 결국 소스를 은직하는 개념이다.

Life Cycle

  • https://github.com/wojtekmaj/react-lifecycle-methods-diagram
  • LifeCycle Methods
  • Mount
    • constructor() : 페이지 로드 되고 컴포넌트가 처음 만들어질때 실행할 코드들을 작성한다. 초기 설정 및 State를 정할 때 사용한다.
    • static getDerivedStateFromProps(nextProps, prevState) : 리턴타입으로 JavaScript Object를 주어야 한다. 리턴된 Object는 State에 반영된다.
    • render() : 이 메서드는 React Component라면 필수로 가지로 가지고 있는 메소드이다. 이 메소드에는 상태를 변경한다던가 하는 사이드 이펙트가 있으면 안된다.
    • componentDidMount() : 컴포넌트가 DOM에 추가 된 후 실행된다.
  • Update
    • shouldComponentUpdate : 리턴타입으로 True, False를 주어야 하며 리턴되는 결과에 따라 DOM에 리렌더링 여부를 결정한다.
    • getSnapshotBeforeUpdate : Virtual DOM이 실제 DOM에 반영되기 직전에 실행된다. 이 메서드에선 현재의 props와 state를 접근 가능하다.
  • UnMount
    • ComponentWillUnMount : DOM에서 컴포넌트가 지워질 때 실행된다.

JSX

  • 자바스크립트의 문법 확장판이다.

rerendering 최소화

  • React 의 Virtual DOM 의 ReRendering은 4 가지 상황에서 발생된다.
    • 부모 Component 가 Rendering 되서, 자식을 비교할때
    • props 가 변경 되었을 때
    • state 가 변경 되었을 때
    • forceUpdate 가 호출되었을 때
  • Memoization : 이중 부모 Component 가 Rendering 되서, 자식을 비교할때, 자식의 props가 변경되지 않았지만, ReRendering되는것은, 불필요한 작업일 수 있다. 특히 거대한 웹을 만들다보면 Node Tree가 깊어지고, 자식들이 많아지면, 비교 해야하는 코드도 많아진다. Component 의 props 정보를 저장해두고, 동일한 props 가 입력되 었을 때 ReRendering를 막는다면 성능을 올릴 수 있을 것이다.
  • shouldComponentUpdate : update 시점의 componentWillUpdate 이전에 발생한다. 이를 이용하면, 불필요한 Rendering 과 자식들의 비교를 막아 성능을 올릴 수 있다.
  • React.memo : props 가 변경 되었을때, 얕은 비교 로, Rerendering 여부를 결정할 수 있다.

windowing

  • 많은 데이터를 list로 만들게 되면 초기 렌더링이 너무 오래 걸린다. 사용자 입장에서 매우 불편하여 이것을 해결하기 위해서 list중에 사용자에게 보이는 부분만 rendering 시키는 기법이다.
  • 라이브러리 사용 : 다량의 데이터로 list를 만들경우 react-window라는 라이브러리로 windowing을 하면 사용자 경험을 증진시키는 데 좋은 영향을 준다.
  • https://codesandbox.io/s/5wqo7z2np4

react 보안

  • XSS방어

    • const title = response.potentiallyMaliciousInput;
      const element = <h1>{title}</h1>;
      
    • ReactDOM은 JSX에 삽입된 모든 값을 렌더링하기 전에 탈출하므로 앱에 명시적으로 작성되지 않은 내용은 주입되지 않고, 모든 항목은 렌더링 되기 전에 문자열로 반환된다. 이런 특성으로 XSS공격을 방지할수 있다.

Redux?

  • 리덕스(Redux)는 JavaScript app을 위한 예측 가능한 state container이다. 리액트 뿐 아니라 Augular, jQuery, vanilla JavaScript 등 다양한 framework와 작동되게 설계되었다. 즉, 리액트만을 위한 Library는 아니다.

    Redux == React Redux?

    • 정답은 ‘아니다’이다. Redux는 상태 관리 라이브러리로, 상태관리 패턴인 Flux의 일부를 변형하여 간단하게 상태 관리가 가능하도록 만들었고, 제이쿼리, 일반 자바스크립트, 다른 SPA 프레임워크 등 다양한 환경에서 사용가능하도록 제작되었다.
    • Redux의 상태관리 기법을 리액트 컴포넌트에 그대로 사용하게 되면, Redux와 리액트 컴포넌트간 의존성이 높아져 컴포넌트의 재사용성이 떨어지게 된다. 이것을 해결하기 위해 컨테이너와 컴포넌트를 분리하여 리덕스 관련 작업은 컨테이너에서, 그 외의 컴포넌트의 본질적 기능은 기존의 props, state 를 그대로 사용하는 전통적인 리액트 컴포넌트 형태로 작성되도록 하여 컴포넌트의 재사용성을 높이도록 하고 있다. 그런데 이러한 컨테이너를 분리하는 패턴을 컴포넌트마다 일일히 작성하는 것은 번거로우며, 나중에 컴포넌트에 props가 추가되거나 삭제될 때 이러한 부분의 처리를 일일히 대응해야 한다는 단점이 있다.
    • React Redux는 이러한 상황에서 컨테이너와 컴포넌트의 분리를 편리하게 해주는 리액트 커뮤니티에서 개발된 라이브러리이다. 컨테이너 작성 부분을 간단하게 해주며, props의 구성 변경에 대해서도 신경쓸 필요가 없게 된다.

    Redux를 사용하는 이유?

    • 대규모 애플리케이션에서 상태 관리를 편하게 하기 위해서다. 리액트에서 컴포넌트간 props를 통해 데이터를 주고받는 패턴은 애플리케이션의 규모가 켜지면 커질수록 상태 관리가 매우 복잡해지게 된다. 예를 들어 루트 컴포넌트 밑에 만 개의 하위 컴포넌트가 있다고 할 때, 이 중 루트 컴포넌트에 영향을 줄 수 있는 하나의 값이 바뀌었는데 그 값을 루트 컴포넌트를 통해 다른 컴포넌트도 사용하고 있다면 기존 패턴에서는 이러한 변경 내용에 일일히 대응하는 코드를 작성하기가 어렵다.

    • 하지만 Redux를 이용하면 중앙에서 상태 관리를 하는 저장소(store)가 있고, 변경 내용이 이 저장소를 통해 dispatch(변경 내용이 저장소에 저장, 갱신됨)되고, 그 내용을 참고하는 다른 컴포넌트들이 subscribe(변경 내용을 감지해 컴포넌트의 스테이트를 갱신) 하는 방식으로 props 패턴을 사용하지 않고도 편리하게 상태 관리를 할 수 있다.

CodeSplit

  • 번들링은 훌륭하지만 여러분의 앱이 커지면 번들도 커진다. 특히 큰 규모의 서드 파티 라이브러리를 추가할 때 실수로 앱이 커져서 로드 시간이 길어지는 것을 방지하기 위해 코드를 주의 깊게 살펴야 한다.
  • 번들이 거대해지는 것을 방지하기 위한 좋은 해결방법은 번들을 “나누는” 것이다. 코드 분할은 런타임에 여러 번들을 동적으로 만들고 불러오는 것으로 Webpack, Rollup과 Browserify (factor-bundle) 같은 번들러가 지원하는 기능이다.
  • 코드 분할은 여러분의 앱을 “지연 로딩” 하게 도와주고 앱 사용자에게 획기적인 성능 향상을 하게한다. 앱의 코드 양을 줄이지 않고도 사용자가 필요하지 않은 코드를 불러오지 않게 하며 앱의 초기화 로딩에 필요한 비용을 줄여준다.

마무리

개인적으로 테스틑 진행해보면서 React의 본질은 사용자 정의 태그를 만들고, 재상용성을 높여 유지보수가 강력해지는데 있다고 생각한다. 그러나 이 본질이 우리가 유지보수하고 있는 서비스에 얼마나 적합한지에 대한 의문에 답이 될 수 없다. 계속해서 사용해보면서 어떤 부분에 가장 적절하게 쓰일 수 있는지 공부할 필요가 있다.