ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • React 16 에 추가된 기능들
    Knowledge/React 2019. 12. 18. 19:01
    반응형

    React 16 마스터하기 강의를 듣고 정리한 내용입니다.

     

    • Fragment

    이전 버전에선 하나의 element만 return 할 수 있는 React의 특성 때문에 여러 개의 태그를 리턴하기 위해선 하나의 부모 태그가 필요했고 이 때문에 의미 없는 태그가 들어가곤 했습니다.

     

    그러나 Fragment를 활용하면 예를 들어

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    import React, { Component, Fragment } from 'react';
     
    class ReturnTypes extends Component {
      render() {
        return (
          <Fragment>
            <header/>
            <div />
            <footer />
          </Fragment>
        );
      }
    }
     
    function App() {
      return (
        <div className="App">
          <ReturnTypes></ReturnTypes>
        </div>
      );
    }
     
    export default App;
     

     

    위와 같이 header, div, footer 태그를 Fragment로 감싸 Return 하면  

     

    위와 같이 Fragment로 감싸 리턴한 태그들만 element 목록에 나타나는 걸 확인할 수 있습니다

     

    • return string

    엘리먼트가 아닌 string만 return하는 것도 가능해졌습니다.

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    import React, { Component, Fragment } from 'react';
     
    class ReturnTypes extends Component {
      render() {
        return "hello";
      }
    }
     
    function App() {
      return (
        <div className="App">
          <ReturnTypes></ReturnTypes>
        </div>
      );
    }
     
    export default App;
     

    • createPortals

    react는 root 안에서만 작동합니다. 그러나 createPortals를 활용하면 root 밖에 있는 html 엘리먼트에 접근할 수 있습니다. 

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    <!DOCTYPE html>
    <html lang="en">
      <head>
        <meta charset="utf-8" />
        <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <meta name="theme-color" content="#000000" />
        <meta
          name="description"
          content="Web site created using create-react-app"
        />
        <title>React App</title>
      </head>
      <body>
        <noscript>You need to enable JavaScript to run this app.</noscript>
        <!-- 주목 -->
        <header>
          <h1>Can't touch this</h1>
          <span id="touchme"></span>
        </header>
        <!-- 주목 -->
        <div id="root"></div>
      </body>
    </html>
     
        <!--  index.html  -->

     

    위와 같이 root div 형제 효소인 header 엘리먼트 내부엔 기존 react로는 접근할 수 없지만 

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    import React, { Component, Fragment } from 'react';
    import { createPortal } from "react-dom";
    // createPortal은 react-dom에 있다
     
    class Portals extends Component {
      render() {
        return createPortal(<Message />,document.getElementById("touchme"));
      }
    }
     
    const Message = () => "Just touched it";
     
    class ReturnTypes extends Component {
      render() {
        return "hello";
      }
    }
     
    function App() {
      return (
        <div className="App">
          <ReturnTypes></ReturnTypes>
          <Portals></Portals>
        </div>
      );
    }
     
    export default App;
     

     

    위와 같이 createPortal 메소드에 인자로 메세지와 선택자를 활용해 특정한 element를 집어넣으면

     

    접근할 수 있게 되었습니다.

     

    • Error Boundaries with Higher Order Components

    이전 버전에서는 컴포넌트의 한 부분에서 에러가 발생하면 다음 Render가 진행되지 않아 전체 UI가 로드되지 않았습니다. 그러나 Error Boundary를 활용하면 에러가 발생한 경우 대체 component를 렌더링해 전체 UI가 망가지는 걸 막을 수 있습니다

     

    예제 코드는 아래와 같습니다

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    import React, { Component, Fragment } from 'react';
    import { createPortal } from "react-dom";
     
    const BoundaryHOC = ProtectedComponent =>
      class Boundary extends Component {
        state = {
          hasError: false
        };
        componentDidCatch = () => {
          this.setState({
            hasError: true
          });
        };
        render() {
          const { hasError } = this.state;
          if (hasError) {
            return <ErrorFallback />;
          } else {
            return <ProtectedComponent />;
          }
        }
      };
     
      // Higher Oreder Components를 활용해 Error Boundary를 활용하는 예
     
      // ProtecteComponent를 함수로 받아
      // componentDidCatch를 활용해 error 발생을 감지하면
      // Proteced Component 대신 ErrorFallback을 반환해 전체 UI가 깨지는 걸 막는다
     
    class ErrorMaker extends Component {
      state = {
        friends: ["kyeo-ul""guem-ja"]
      }
     
      componentDidMount = () => {
        setTimeout(() => {
          this.setState({
            friends: undefined
          });
        }, 2000);
      };
     
      render() {
        const { friends } = this.state;
        return friends.map(friend => `${friend} `)
      }
    }
    // 2초뒤 에러를 발생시킴
     
    const PErrorMaker = BoundaryHOC(ErrorMaker);
    // BoundaryHOC로 보호
     
    class Portals extends Component {
      render() {
        return createPortal(<Message />, document.getElementById("touchme"));
      }
    }
     
    const PPortals = BoundaryHOC(Portals);
    // BoundaryHOC로 보호
     
     
    const ErrorFallback = () => "Sorry something went wrong";
    // 에러 발생 시 리턴할 문구
     
    const Message = () => "Just touched it";
     
    function App() {
      return (
        <div className="App">
          <PPortals />
          <PErrorMaker />
        </div>
      );
      // 보호하고 있는 component 리턴
    }
     
    export default App;
     

     

    위와 같이 코드를 작성하면

     

    제대로 로드 되었다가

     

     

    2초 뒤 에러가 발생하더라도 경고 문구를 닫아보면

     

    대체 component(ErrorFallback) 가 렌더링 되어 전체 UI가 깨지지 않은 걸 확인할 수 있습니다.

     

    • this.setState(null)

    react16에서는 setState(null)을 활용해 state와 component 업데이트를 제어할 수 있게 되었습니다. 예를 들어

     

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    import React, { Component } from "react";
     
    const MAX_PIZZAS = 20;
     
    class Controlled extends Component {
      state = {
        pizzas: 0
      };
      render() {
        const { pizzas } = this.state;
        return (
          <button onClick={this._handleClick}>{`I have eaten ${pizzas} ${
            pizzas === 1 ? "pizza" : "pizzas"
          }`}</button>
        );
      }
      _handleClick = () => {
        this.setState(eatPizaa);
        // eatPizaa를 활용해 state를 업데이트 합니다
      };
    }
     
     
    const eatPizaa = (state, props) => {
      // eatPizaa에선
      const { pizzas } = state;
      if (pizzas < MAX_PIZZAS) {
        return {
          pizzas: pizzas + 1
          // pizzas가 MAX_PIZZAS 보다 작을 경우 1 즈악한 pizzas를 리턴하지만
        };
      } else {
        return null;
        // 그렇지 않으면 null을 리턴합니다
      }
    };
     
    class App extends Component {
      render() {
        return <Controlled />;
      }
    }
     
    export default App;

     

    코드를 위와 같이 작성하면

     

    이렇게 null이 리턴되는 경우 component와 state가 더이상 업데이트 되지 않는 걸 확인할 수 있습니다.


    참조

     

    React 공식 가이드 - 에러 경계

     

    반응형

    댓글

Designed by Tistory.