[컴] mobx + reactjs 사용

 redux mobx

 

mobx + reactjs 사용

사용

설치

MobX 6 부터는 javascript 와의 호환성을 위해 decorator들을(@observable 등) 없앴다고 한다.

React 에서 사용하기

예제

  • observer 는 observable 을 바라보고 있다가 observable 이 변하면 반영을 하게 된다.
import { makeAutoObservable } from "mobx"
import { observer } from "mobx-react"

class Timer {
  secondsPassed = 0;
  sm = 0;

  constructor() {
    makeAutoObservable(this);
  }

  increaseTimer() {
    this.secondsPassed += 1;
    this.sm += 2;
  }
}

const myTimer = new Timer();

setInterval(() => {
  myTimer.increaseTimer();
}, 1000);


// A function component wrapped with `observer` will reacts to any
// future change in an observable it used before

// functional version
//
// const TimerView = observer(
//   ({ timer }: { timer: Timer }) => (
//   <div>
//     <span>Seconds passed: {timer.secondsPassed}</span>
//     <span>Seconds passed: {timer.sm}</span>
//   </div>
// ));

type TimerViewProp = {
  timer: any
}

const TimerView = observer(
  class TimerView extends React.Component<TimerViewProp> {
    render() {
      const { timer } = this.props
      return (
        <div>
          <span>Seconds passed: {timer.secondsPassed} </span>
          <span>Seconds passed: {timer.sm} </span>
        </div>

      )
    }
  }
)

ReactDOM.render(<TimerView timer={myTimer} />, document.body);

redux 대비 mobx 의 장점

  1. 반복되는 code 가 적다. redux 는 reducer, actions, containers, components 를 계속해서 만들어야 한다.
    • 그래서 build time 이 줄어든다.
  2. 배우기 쉽다.(learning curve 가 낮다.)

Mobx의 state 은 mutable 이다. Redux 가 함수들이 pure function 일때 scale 하기가 용이하다.

vs Redux

특정 test 에서 mobx 가 redux 보다 더 빠르다고 나온다.

See Also

  1. Optimizing React component rendering · MobX
  2. Defining data stores · MobX

Reference

  1. Choosing MobX over Redux for large-scale Enterprise Applications - DEV

[컴] create-react-app 사용 + typescript

 typecript 사용 / react typescript /

create-react-app 사용

  1.  Getting Started : npx create-react-app my-app --template typescript : my-app 이라는 기본 reactjs app 구조를 만들어 준다.
  2.  Adding a Sass Stylesheet: npm i node-sass --save-dev 만 해주면 된다. 나머지는 설정이 다 되어 있다.
  3.  Available Scripts : npm eject: 만약 webpack.config 를 직접 수정하고 싶다면 npm eject 를 이용하면 된다. 하지만 npm reject 를 한 번 사용하면 되돌릴 수 없으니 참고하자.
  4. Class Components | React TypeScript Cheatsheets


> my-react-app@0.1.0 eject d:\a\prog\nodejs\my-react-app
> react-scripts eject

NOTE: Create React App 2+ supports TypeScript, Sass, CSS Modules and more without ejecting: https://reactjs.org/blog/2018/10/01/create-react-app-v2.html

? Are you sure you want to eject? This action is permanent. Yes
Ejecting...

Copying files into d:\a\prog\nodejs\my-react-app
  Adding \config\env.js to the project
  Adding \config\getHttpsConfig.js to the project
  Adding \config\modules.js to the project
  Adding \config\paths.js to the project
  Adding \config\pnpTs.js to the project
  Adding \config\webpack.config.js to the project
  Adding \config\webpackDevServer.config.js to the project
  Adding \config\jest\cssTransform.js to the project
  Adding \config\jest\fileTransform.js to the project
  Adding \scripts\build.js to the project
  Adding \scripts\start.js to the project
  Adding \scripts\test.js to the project

Updating the dependencies
  Removing react-scripts from dependencies
  Adding @babel/core to dependencies
  Adding @svgr/webpack to dependencies
  Adding @typescript-eslint/eslint-plugin to dependencies
  Adding @typescript-eslint/parser to dependencies
  Adding babel-eslint to dependencies
  Adding babel-jest to dependencies
  Adding babel-loader to dependencies
  Adding babel-plugin-named-asset-import to dependencies
  Adding babel-preset-react-app to dependencies
  Adding camelcase to dependencies
  Adding case-sensitive-paths-webpack-plugin to dependencies
  Adding css-loader to dependencies
  Adding dotenv to dependencies
  Adding dotenv-expand to dependencies
  Adding eslint to dependencies
  Adding eslint-config-react-app to dependencies
  Adding eslint-loader to dependencies
  Adding eslint-plugin-flowtype to dependencies
  Adding eslint-plugin-import to dependencies
  Adding eslint-plugin-jsx-a11y to dependencies
  Adding eslint-plugin-react to dependencies
  Adding eslint-plugin-react-hooks to dependencies
  Adding file-loader to dependencies
  Adding fs-extra to dependencies
  Adding html-webpack-plugin to dependencies
  Adding identity-obj-proxy to dependencies
  Adding jest to dependencies
  Adding jest-environment-jsdom-fourteen to dependencies
  Adding jest-resolve to dependencies
  Adding jest-watch-typeahead to dependencies
  Adding mini-css-extract-plugin to dependencies
  Adding optimize-css-assets-webpack-plugin to dependencies
  Adding pnp-webpack-plugin to dependencies
  Adding postcss-flexbugs-fixes to dependencies
  Adding postcss-loader to dependencies
  Adding postcss-normalize to dependencies
  Adding postcss-preset-env to dependencies
  Adding postcss-safe-parser to dependencies
  Adding react-app-polyfill to dependencies
  Adding react-dev-utils to dependencies
  Adding resolve to dependencies
  Adding resolve-url-loader to dependencies
  Adding sass-loader to dependencies
  Adding semver to dependencies
  Adding style-loader to dependencies
  Adding terser-webpack-plugin to dependencies
  Adding ts-pnp to dependencies
  Adding url-loader to dependencies
  Adding webpack to dependencies
  Adding webpack-dev-server to dependencies
  Adding webpack-manifest-plugin to dependencies
  Adding workbox-webpack-plugin to dependencies

Updating the scripts
  Replacing "react-scripts start" with "node scripts/start.js"
  Replacing "react-scripts build" with "node scripts/build.js"
  Replacing "react-scripts test" with "node scripts/test.js"

Configuring package.json
  Adding Jest configuration
  Adding Babel preset

Running npm install...
audited 1644 packages in 5.619s

71 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

Ejected successfully!

warning: LF will be replaced by CRLF in config/env.js.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in config/getHttpsConfig.js.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in config/jest/cssTransform.js.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in config/jest/fileTransform.js.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in config/modules.js.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in config/paths.js.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in config/pnpTs.js.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in config/webpack.config.js.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in config/webpackDevServer.config.js.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in scripts/build.js.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in scripts/start.js.
The file will have its original line endings in your working directory
warning: LF will be replaced by CRLF in scripts/test.js.
The file will have its original line endings in your working directory
Staged ejected files for commit.

Please consider sharing why you ejected in this survey:
  http://goo.gl/forms/Bi6CZjk1EqsdelXk1

Reference

  1. Create React App · Set up a modern web app by running one command. 

 

[컴][nodejs] Express or Hapi

비교 / express , hapi 성능 비교 /벤치

Express or Hapi

Express, Kraken

express 기반의 여러 framework

expressjs 를 기반으로 framework 들이 여러개가 존재한다.(참고: Frameworks built on Express)

distributed application

typescipt

단점 그리고 kraken

ref. 3 에 의하면 PayPal 의 사용후기에는 구조에 특정한 제약이 없어서 이것이 여러 개발팀에서 사용하기에는 적합하지 않았다. 그래서 krakenjs 을 만들었다.

Hapi

Walmart 에서 블랙프라이데이에 대한 처리를 하기위해 만들었다고 한다.

hapi 를 사용하는 회사

Hapi vs Express

See Also

  1. Express vs Koa (and Hapi). Node Js and framework introduction | by Théo Malaper | Medium

Reference

  1. 10 Best NodeJS Frameworks for Developers [Updated]
  2. Which Node.js framework is Ideal for Usage: Choose Amidst Express.js, Koa.js or Sails.js
  3. Node.js at PayPal | by PayPal Engineering | PayPal Engineering | Medium, 2013-11-22

[컴][nodejs] mocha, chai, sinon

test framework /mock up / bdd / tdd / node에서 tdd / test unittest / test case

mocha, chai, sinon

mocha with typescript

typescript 와 mocha 를 이용하는 방법은 아래 링크를 참고하자.

npm install mocha chai ts-node --save-dev
mocha --recursive -r ts-node/register ./src/ts/test/**/*.test.ts

cheatsheets

sinon

stub 는 type 들을 다 맞춰줘야 한다. 그래서 간단히 만들때는 fake 가 더 낫긴 하다. 하지만 확실히 정확한 test 를 위해서는 type 을 맞추는 stub 가 나을 수 있다.

ts-node + mocha 의 debugging 을 위한 vscode launch.js

trace는 진단로그(diagnostic log) 를 찍어준다.
sourceMaps 은 sourceMap 이 있는 js 인 경우 sourceMap 을 사용한다.
2개의 옵션이 없어도 ts 에 대한 debug 가 잡히는 것 같다.
 {  
    "version": "0.2.0",  
    "configurations": [  
        {  
            "args": [  
                "-u",  
                "bdd",  
                "--timeout",  
                "999999",  
                "--colors",  
                "-r",  
                "ts-node/register",  
                "--recursive",  
                "${file}"  
            ],  
            "internalConsoleOptions": "openOnSessionStart",  
            "name": "Mocha Tests Current File",  
            "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha",  
            "request": "launch",  
            "skipFiles": [  
                "/**"  
            ],  
            "type": "pwa-node",  
            "trace": true,  
            "sourceMaps": true,  
       }  
    ]  
}

unittest examples

특정 object.method 안에서 "다른 object.method" 의 parameter 를 확인하기 위한 방법

export class MyRequest {
  host = 'bunjang.co.kr';
  version = 4;
  constructor() {

  }

  async retrieve() {
    const customAxios =
      this._getCustomAxios();
    // const now = new Date();
    const utcNow = moment().utc();
    // ex: 2020918080254
    const requestId = utcNow.format("YYYYMDDHHmss");
    const response = await customAxios.get(`/api/1/product/${startPid}/detail_info.json`, {
      params: {
        version: this.version,
        // get random 7 digit which starts with 1
        stat_uid: this._getStatUid()
      }
    })
  }

  _getCustomAxios() {
    const customAxios = axios.create({
      baseURL: `https://test/`
    })
    return customAxios;
  }
}
import sinon, { spy } from 'sinon';
import { expect } from 'chai';
import { AxiosResponse } from 'axios';

describe('Reuquest', () => {
    it('should retrieve', async () => {

        const spyGet = spy((url: string, param: any): AxiosResponse => {
            return {
                data: {
                    list: [],
                },
                status: 200,
                statusText: "",
                headers: {},
                config: {},
            };
        });

        const fakeGet = sinon.fake.returns({
            get: spyGet
        })

        const myReq = new MyRequest();

        sinon.replace(
            myReq,
            '_getCustomAxios',
            fakeGet);

        await myReq.retrieve();
        sinon.restore();

        // get 을 1번째 call 했을 때의 argument중 2번째(args[1])
        const actualParam = { ...spyGet.getCall(0).args[1].params };
        expect(actualParam).to.deep.equal({
            test1: 'mytest',
            version: 'mytest-ver',
        });
    });

}); 

[컴][nodejs] objection.js 사용하기

orm nodejs orm / orm 추천 /laravel / query builder


objection.js 사용하기

typescript example


사용

기본적으로 모든 query 는 특정 Model 로 부터 시작한다.(참고)

insert: objection.js/api.ts at master · Vincit/objection.js · GitHub

update: objection.js / update.ts example

typescript 에서 model 작성: objection.js github /tests/ts/fixtures/person.ts 

validation

  • jsonSchema 가 있으면 update/insert 시 자동적으로 호출됨.
  • required(required: [],) 는 그래서 update 때도 필수적으로 필요한 부분을 적어야 한다. 안그러면 update 시점에도 required 부분이 적용된다.
  • objection.js/validation.md
  • objection.js/Animal.ts: ts version jsonSchema 예제 확인 가능  

modifier

query builder 의 확장 : 이것의 위의 modifier 와 비슷하다.

raw query : Raw queries > Examples

transaction :

upsert with knex

vs bookshelf.js

examples

// Mocha Test 코드
var assert = require('assert');
var { Tag } = require('../../../../src/js/app/model/tag')
var { insertOrUpdate } = require('../../../../src/js/lib/db')
var { Model, transaction, DBError } = require('objection')
var Knex = require('knex')
var { knexConfig } = require('../../../../src/js/knexconfig')

// Initialize knex.
const knex = Knex({
  client: 'sqlite3',
  useNullAsDefault: true,
  connection: {
    filename: ':memory:',
  },
  pool: {
    afterCreate: (conn, cb) => {
      conn.run('PRAGMA foreign_keys = ON', cb);
    }
  }
});

// Bind all Models to a knex instance. If you only have one database in
// your server this is all you have to do. For multi database systems, see
// the Model.bindKnex() method.
Model.knex(knex);

const createTableTag = async function createTableTag(knex) {
  const has = await knex.schema.hasTable('tag')
  if (!has) {
    const res = await knex.schema.createTable('tag', function (table) {
      table.increments(); // integer id
      table.timestamps();
      // name
      table.string('name');
    });
    return res;
  }

};

describe('Connection', () => {


  it('it should FIND a tag-name or INSERT', async () => {
    // Tag.knex() 대신에 knex 를 사용하면, 현재 존재하는 db 의 table 을 이용하게 된다.
    const res2 = await createTableTag(Tag.knex());
    await insertOrUpdate(Tag.knex(), Tag.tableName, { name: 'test111' });

  });

});

migration

init 을 하면 knexfile.js 가 만들어진다. migrate:make <name> 을 하면 <name> 을 갖는 migration template을 하나 만들어준다. 그럼 이 template 안에 db migration 관련 내용을 적으면 된다.

.\node_modules\.bin\knex.cmd init
.\node_modules\.bin\knex.cmd migrate:make my_table_name
// migration file
exports.up = function(knex) {
  return knex.schema
    .createTable('logs', (table) => {
      table.increments('id').primary()

      // table
      //   .integer('type').unsigned()
      //   .references('id').inTable('persons')
      //   .onDelete('SET NULL')
      //   .index()

      table.integer('type')
      table.json('log')
    }) 
};

exports.down = function(knex) {
  return knex.schema
    .dropTableIfExists('logs') 
};  

migration file 을 다 만든 후 migrate:latest 를 실행하면 된다.

production 인 경우, windows 기준으로 아래처럼 실행하면 된다. 이때 현재 실행하는 directory 위치에서 knexfiles.jsmigrations/*.js 파일을 가져다 migration 을 실행한다.

참고로, npm run script 로 넣어서 실행하는 경우 directory 가 안맞아서 안된다. (option 으로 path 를 변경해도 안됐다.)

set NODE_ENV=production
cd <proj_root>
.\node_modules\.bin\knex.cmd migrate:latest

References

  1. Objection.js

 

 

[컴][nodejs] bookshelf.js 를 사용하기

 knex orm / database builder / nodejs / node js


bookshelf.js 사용하기

typescript 에서 bookshelf.js 를 사용하기

예제를 Bookshelf.js -> Examples 와 비교해 보자.


transaction

위의 comment 에 따르면, transaction block 에서 Error 가 나오지 않으면 자동으로(implicitly) commit() 이 되고, error 가 발생하면 자동으로 rollback() 을 호출한다.

bookshelf 예제

  1. javascript - How to fix nested structure in bookshelfjs transaction - Stack Overflow
  2. lock for update: bookshelf/model.js at d729ae7069041fcec4aaf5bf5127261ec660da0c · bookshelf/bookshelf · GitHub
  3. raw query : bookshelf/inserts.js at a626e9828c410add841def50cd95d3a7e30abe77 · bookshelf/bookshelf · GitHub

See Also

  1. Objection.js: query builder 를 제공한다.

[컴][DB] ORM 의 장단점

 object relational mapping

ORM 의 장단점

장점

  1. 표준화, 추상화
  2. sql 의 학습이 필요없다.
  3. portable : 다른 db 로 migrate 하기 쉽다.
  4. 여러 db 를 사용하는 경우에 하나의 언어로 query 를 통일해서 사용할 수 있다.
  5. 복잡한 데이터의 처리, 삭제(cleaning) 등은 code 로 하는 것이 대체로 쉽다.
  6. data 를 code 를 통해 초기화 할 수 있다.
  7. system 이 runtime 에 data 사용을 구현하게 해준다.
  8. 필요에 따라서 개발 단계에서 유연하게 사용을 조정할 수 있다.(adapt)

단점

  1. 복잡한 query 를 구현하기 어렵다.
  2. 비효율적이 될 수 있다. : 간단한 query 도 orm 에 맞춰야 하고, 최적화된 query 보다는 ORM 의 기준으로 효과적인 코딩을 한다.
  3. 새로운 언어: sql 과 다른 문법이다.

Reference

  1. Which Query Builder/ORM should you use for Nodejs