immutable-js with TypeScript

2woongjae@gmail.com

Mark Lee (이웅재)

  • Studio XID inc. ProtoPie Engineer
  • Seoul.JS 오거나이저
  • 타입스크립트 한국 유저 그룹 오거나이저
  • 일렉트론 한국 유저 그룹 운영진
  • Seoul.js 오거나이저
  • Microsoft MVP - Visual Studio and Development Technologies
  • Code Busking with Jimmy
    • https://www.youtube.com/channel/UCrKE8ihOKHxYHBzI0Ys-Oow

facebook/immutable-js

immutable-js  22348

2018.02

immutable-js 주요 특징

  • 한번 만들어지면 안변하는 데이터를 이뮤터블 데이타라 한다.
  • 자바스크립트는 객체 내부의 값을 변경해도 같은 레퍼런스를 유지하기 때문에 객체 내부 값을 일일이 비교하지 않으면 정확히 모든 값이 같은지 알수 없다.
  • A 라는 이뮤터블 데이터에서 특정 값을 수정하려면, 기본적으로는 B 라는 객체를 새로 만들고 A 의 모든 값을 B 로 복사해야한다.
    • 이 것은 비용이 많이 든다.
    • 그래서 나온 아이디어로 구현해낸 것이 immutable-js
  • react 의 어느 부분에서 사용하면 좋을까
    • 첫번째, 리덕스의 리듀서 부분
    • 두번째, Pure 컴포넌트
  • 성능 이야기

기본 사용법

const { Map } = require("immutable");
const map1 = Map({ a: 1, b: 2, c: 3 });
const map2 = map1.set('b', 50);
map1.get('b') + " vs. " + map2.get('b') // 2 vs. 50

const { List } = require('immutable')
const list1 = List([ 1, 2 ]);
const list2 = list1.push(3, 4, 5);
const list3 = list2.unshift(0);
const list4 = list1.concat(list2, list3);
assert.equal(list1.size, 2);
assert.equal(list2.size, 5);
assert.equal(list3.size, 6);
assert.equal(list4.size, 13);
assert.equal(list4.get(0), 1);

Redux Reducer Example

이전 작업

import { BuildActions } from '../actions';
import * as types from '../constants';

export interface Build {
  text: string;
  completed: boolean;
  id: number;
}

const initialState: Build[] = [];

export interface Builds {
  builds: Build[];
}

export function builds(state: Build[] = initialState, action: BuildActions) {
  switch (action.type) {
    case types.ADD_BUILD:
      return [
        ...state,
        {
          id: state.reduce((maxId, todo) => Math.max(todo.id, maxId), -1) + 1,
          completed: false,
          text: action.text
        }
      ];

    case types.DELETE_BUILD:
      return state.filter(todo => todo.id !== action.id);

    default:
      return state;
  }
}

immutable 로 전환

import { BuildActions } from '../actions';
import * as types from '../constants';
import { List } from 'immutable';

export interface Build {
  text: string;
  completed: boolean;
  id: number;
}

const initialState: Build[] = [];

export interface Builds {
  builds: Build[];
}

export function builds(state: Build[] = initialState, action: BuildActions) {
  switch (action.type) {
    case types.ADD_BUILD:
      const newState: List<Build> = List(state).push({
        id: state.reduce((maxId, todo) => Math.max(todo.id, maxId), -1) + 1,
        completed: false,
        text: action.text
      });
      console.log(newState);
      return newState;

    case types.DELETE_BUILD:
      return List(state).filter(todo => {
        if (todo === undefined) {
          return false;
        }
        return todo.id !== action.id;
      });

    default:
      return state;
  }
}

Pure Component Example

프로젝트 준비

~/Project/workshop-201801 
➜ npx create-react-app immutable-ts-pure-component --scripts-version=react-scripts-ts

~/Project/workshop-201801 took 1m 47s 
➜ cd immutable-ts-pure-component

Project/workshop-201801/immutable-ts-pure-component is 📦 v0.1.0 via ⬢ v8.9.4 
➜ npm i immutable -D            
+ immutable@3.8.2
added 1 package in 7.387s

App.tsx

import * as React from 'react';
import './App.css';
import Pure from './Pure';

const logo = require('./logo.svg');

class App extends React.Component<{}, { count: number }> {
  state = {
    count: 0
  };
  render() {
    return (
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <h1 className="App-title">Welcome to React</h1>
        </header>
        <p className="App-intro">
          <button
            onClick={() => this.setState({ count: this.state.count + 1 })}
          >
            카운트 업
          </button>
        </p>
        <p>{this.state.count}</p>
        <Pure {...this.state} />
      </div>
    );
  }
}

export default App;

Pure.tsx

import * as React from 'react';

interface PureProps {
  count: number;
}

class Pure extends React.Component<PureProps, {}> {
  shouldComponentUpdate(prevProps: PureProps, prevState: {}) {
    if (prevProps.count > 20) {
      return true;
    }
    return false;
  }
  render() {
    return <div>{JSON.stringify(this.props)}</div>;
  }
}

export default Pure;

[CODEBUSKING WORKSHOP] immutable-js with TypeScript

By Woongjae Lee

[CODEBUSKING WORKSHOP] immutable-js with TypeScript

코드버스킹 워크샵 - React with TypeScript 세번째 (2018년 1월 버전)

  • 1,119