TypeScript with React

TypeScript with React

Typescript with React

Why use TypeScript with React

  • Typescript안에 JSX가 내장되어 있기 때문에 간단한 템플릿 문자열로 작동하는 다른 프레임워크들과 비교했을 때 좋다.
  • Type을 지정해주어야 하기 때문에 강력한 리팩토링과 Type Checking을 할 수 있다.
  • Functions
    • TypeChecking

Bootstrap a TypeScript + React project

필요 항목
  • react
  • react-dom
  • webpack
  • webpack-dev-server
  • typescript
  • @types/react
  • @types/react-dom
  • ts-loader
  • webpack.config.js: webpack을 호출하는 빌드 스크립트
    module.exports = {
     devtool: 'inline-source-map', // 파일 내 브라우저에서 TypeScript 파일을 디버깅 할 수 있도록 지정
     entry: './src/app.tsx', // 응용 프로그램 시작점 지정
     output: {
      patch __dirname + '/public',
      filename: 'build/app.js'
     },
     resolve: {
      extensions: ['.ts', '.tsx', '.js'] // ts, tsx파일을 원본 js파일 확장자와 함께 지원하도록 함
     },
     module: {
      rules: [
      { test: /\.tsx?$/, loader: 'ts-loader' } // webpack에 ts와 tsx 파일의 경우 ts-loader를 사용해야 한다고 암려줌
      ]
     }
    }
    
  • package.json(webpack-dev-server를 실행하고 ./public 폴더를 제공하는 시작 스크립트 추가)
    "scripts": {
     "build": "webpack ./webpack.config.js",
     "start": "webpack-dev-server ./webpack.config.js --content-base ./public"
    }
    
  • index.html
    <html>
     <body>
      <div  id="root"></div>
      <script  src="./build/app.js"></script> // React 응용 프로그램을 렌더링한 다음 webpack에서 생성된 번들을 로드
     </body>
    </html>
    
  • app.tsx
    import  *  as  React  from  'react';
    import  *  as  ReactDOM  from  'react-dom';
    
    ReactDOM.render(
     <div>Hello  world</div>,
     document.getElementById('root')
    );
    
  • npm start -> localhost:8080
    npm run build를 실행. webpack은 코드를 컴파일하고 app.js파일을 디스크에 쓴다.

Create stateless React components using TypeScript

  • App이라는 함수를 만들고 동일한 JSX 요소를 반환하여 이라는 상태를 비 저장 구성 요소로 쉽게 이동
    import * as React from 'react';
    import * as ReactDOM from 'react-dom';
    
    const App = () => <div>Hello world</div>;
    
    ReactDOM.render(
     <App/>,
     document.getElementById('root')
    );
    
  • 속성 추가 (React.SFC<>와 같은 인터페이스나 props를 사용하여 타입을 지정해주는 게 좋음)
    const App = ({message}) => <div>{message}</div>;
    
    ReactDOM.render(
     <App message="Hello world again"/>,
     document.getElementById('root')
    );
    
    // 타입 지정
    const App: React.SFC<{ message: string }> = ({message}) => <div>{message}</div>;
    
    ReactDOM.render(
     <App message="Hello world again"/>,
     document.getElementById('root')
    );
    
    또는
    
    type AppProps = { message: string }
    const App: React.SFC<AppProps> = ({message}) => <div>{message}</div>;
    
    ReactDOM.render(
     <App message="Hello world again"/>,
     document.getElementById('root')
    );
    

Create stateful React Components using TypeScript

React.Component 클래스를 확장하여 Stateful React Components 생성 가능(필요 항목: props와 state)
  • render() 함수 내에서 JSX요소를 반환 가능
    class App extends React.Component {
     render() {
      return (
       <div>Hello world</div>
      );
     }
    }
    
    ReactDOM.render(
     <App/>,
     document.getElementById('root')
    );
    
  • props type 추가
    class App extends React.Component <{
     message: string //this
    }> {
    render() {
     return (
      <App message="Hello again" />, // render()함수에서 사용 가능(string type이 아닌 경우 error!)
      document.getElementById('root')
      );
     }
    }
    
  • React.Component에서 확장된 컴포넌트는 자체 내부 상태를 가질 수 있기 때문에 stateful이라고 한다.
    class App extends React.Component <{
     message: string
    }, {
     count: number,
     }> {
     constructor(props) { //생성자에서 상태 초기화
      super(props);
      this.state = {
       count: 0
      }
     }
     render() {
      return (
       <div>{this.props.message}{this.state.count}</div> // 살재 값 출력
      );
     }
    }
    
  • setState매서드를 이용하여 멤버 함수 호출 가능
    class App extends React.Component <{
     message: string
    }, {
     count: number,
    }> {
     constructor(props) {
      super(props);
      this.state = {
       count: 0
      }
     }
     render() {
      return (
       <div onClick={this.increment}>{this.props.message}{this.state.count}</div>
      );
     }
     increment = () => {
      this.setState({ // this
       count: this.state.count + 1
      });
     }
    }
    
  • inline type으로 정의 가능
    type AppProps = {
     message: string,
    }
    type AppState = {
     count: number,
    }
    class App extends React.Component <ApProps, AppState> {
     ...
    }
    

Publish a React component with TypeScript

TypeScript를 사용하여 React Component 패키지를 만드는 방법 설명
  • fancy라는 node 모듈 이용
    "name": "fancy",
    "version": "0.0.0",
    "license": "MIT",
    "repository": {
    "type": "git",
    "url": "https://github.com/basarat/typescript-react.git"
    },
    "scripts": {}
    
  • tsconfig.json 파일을 만들어 TypeScript 옵션 지정
    {
     "compilerOptions": {
     "sourceMap": true,
     "target": "es5",
     "jsx": "react",
     "declearation": true,
     "outDir": "lib" // 컴파일된 JS 파일의 출력 디렉토리
     },
     "include": [
     "src" // 소스는 src 폴더에 위치
     ]
    }
    
  • package.json 파일에 버전 제공 및 JS 파일 경로 설정
    "scripts": {},
    "peerDependencies": {
     "react": ">=16.0.0"
    },
    {
     "name": "fancy",
     "version": "0.0.0",
     "license": "MIT",
     "main": "lib",
     "types": "lib",
     "repository": {
      ...
     }
    }
    
  • tsconfig.json에서 tsc를 호출하는 빌드 스크립트 설정(라이브 개발을 위해 watch모드에서 build -w를 실행하는 시작 스크립트 추가)
    "scripts": {
     "build": "tsc -p .",
     "start": "npm run build -- -w"
    }
    
  • 빌드 및 실행
    npm install fancy -> npm link fancy, npm link
    import * as React from 'react';
    import * as ReactDOM from 'react-dom';
    import * as { Fancy } from 'fancy';
    
    reactDOM.render(
     <Fancy text={"Hello world"} />,
     document.getElementById('root')
    );
    

Test React components and dom using Enzyme

  • Enzyme: 리액트 테스트 유틸리티, 라이브러리(컴포넌트 테스트)
  • Jest: 테스트 러너(테스트 프레임워크)
  • 컴포넌트 테스트가 유용할 때
  • 컴포넌트 라이브러리
  • 오픈 소스 프로젝트
  • 3rd party 컴포넌트와의 통합
  • 버그 방지

Finally…

강의를 들으면서 동시에 포스팅하다보니 두서 없을 수 있지만… 공부를 했다는 것에 의의를 둡니다:)

댓글

가장 많이 본 글