npx create-react-app 에서 A template was not provided. This is likely because you’re using an outdated version of create-react-app. 에러가 날 때

Problem

CRA 공식 문서대로 npx create-react-app my-app 명령어를 입력했는데

A template was not provided. This is likely because you're using an outdated version of create-react-app.

에러가 나면서 빈 react app이 생성되었다.
훗 뭐 예전에 글로벌로 설치했던 cra 때문이겠지 하고 npm uninstall -g create-react-app 돌리고 재실행했는데 여전히 위에 에러가 났다.

npm list -g 로 글로벌 모듈을 봐도 create-react-app이 없는데 무슨 일이지… 했음

Solution

which create-react-app

명령어로 컴에 아직 cra가 남아있는지 찾는다. 나는 /usr/local/bin/create-react-app 에 있더라.

rm -rf /usr/local/bin/create-react-app

위 명령어로 가뿐하게 지워준다.
다시 npx create-react-app my-app 하면 이젠 template 껴져서 제대로 된다 🙂

[일일코딩 #35] String incrementer

Question

스트링에서 넘버만 따다가 +1 하는것. 자릿수 지키기.

https://www.codewars.com/kata/string-incrementer/javascript

Your job is to write a function which increments a string, to create a new string.

If the string already ends with a number, the number should be incremented by 1.
If the string does not end with a number. the number 1 should be appended to the new string.
Examples:

foo -> foo1

foobar23 -> foobar24

foo0042 -> foo0043

foo9 -> foo10

foo099 -> foo100

Attention: If the number has leading zeros the amount of digits should be considered.

My answer

정규식으로 number만 따다가 +1 해주고 원래 자릿수를 구해서 0을 그만큼 채워줬다.
마음에 안 듦.

function incrementString (str) {
    const numRegex = /[0-9]+/.exec(str);
    if (numRegex) {
        const numStr = numRegex.pop();

        const newNum = Number(numStr) + 1;
        const zeroNums = numStr.length - newNum.toString().length;
        const zeroStr = (zeroNums > 0) ? Array(zeroNums).fill("0").join("") : "";

        return str.replace(numStr, `${zeroStr}${newNum}`)
    }
    return `${str}1`;
}

Others' answer

Azuaron, Nakid..

function incrementString (input) {
    // 맨끝이 not a number면 그냥 + "1" 
    if(isNaN(parseInt(input[input.length - 1]))) return input + '1';

    // "001"을 넘겼다면 match는 001, p1은 00, p2는 1
    return input.replace(/(0*)([0-9]+$)/, function(match, p1, p2) {
        var up = parseInt(p2) + 1;

        // +1한 숫자 자릿수가 원본자릿수보다 크다면 0을 하나 뺀만큼 앞에 붙여주고 아니면 원본 0갯수만큼 붙여주기
        return (up.toString().length > p2.length) ? p1.slice(0, -1) + up : p1 + up;
    });
}
  • String.replace 첫번째 인자에 정규식을 넘길수 있고, 두 번째 인자에 함수를 넘길 수 있구나!
  • 정규식에 ()으로 그룹을 지어서 두번째 이후 인자로 받을 수 있구나
  • String.slice(0, -1)은 마지막 한글자를 떼는거구나

# [일일코딩 #34] Two sum

이건 쉬웠당 15분도 안걸린듯
몇년전에도 풀었던거같다 유명한 문제자너 이름도 익숙하구

Question

링크

Given an array of integers, return indices of the two numbers such that they add up to a specific target.

You may assume that each input would have exactly one solution, and you may not use the same element twice.

Example:

Given nums = [2, 7, 11, 15], target = 9,

Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].

My answer

어제도 썼던 indexOf 써서 풀었당
for문을 돌리면서 target에서 el을 뺀 diff값이 나머지 array에 있는지 확인하면 됨.

var twoSum = function(nums, target) {
    for(let i=0; i<nums.length; i++) {
        const foundIdx = nums.indexOf(target - nums[i]);
        if (foundIdx >= 0 && foundIdx !== i) {
            return [i, foundIdx]
        }
    }
};

옛날에 푼걸 봐볼까

걍 똑같이 풀었네..

var twoSum = function(nums, target) {
  for (var i = 0; i <nums.length; i++) {
    var lastIdx = nums.lastIndexOf(target - nums[i]);
    if(lastIdx > 0) return new Array(i, lastIdx);
  }
};

[일일코딩 #33] Remove Duplicates from Sorted Array

일일코딩 #32가 2017년 6월이었고, 오늘의 일일코딩 #33은 2019년 11월이다. 2년이 넘었다.
2년만에 푼 알고리즘 문제는 아주 노답이었다고 할 수 있다.
Leetcode easy난이도 문제인데 한시간 걸렸거든.
와 정말 부끄럽다.

영어 설명을 제대로 읽지 않은 탓도 있다.
Array의 duplicated된 엘리먼트를 지우라기에 당연히 지워진 array를 반환하는줄 알았지.
그런데 반환값은 Array의 length뿐이었고 Params로 온 Array의 reference를 받아 원본 Array를 중복 없이 만드는거였다. 메모리 새로 안쓰고.

담엔 잘 읽어.

Question

Leetcode 링크
Given a sorted array nums, remove the duplicates in-place such that each element appear only once and return the new length.

Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory.

즉 아래와 같다.

removeDuplicates([1,1,2]); // returns 2 (원본 Array는 [1, 2]로 modify됨)

removeDuplicates([0,0,1,1,1,2,2,3,3,4]); // returns 4 (원본 Array는 [0, 1, 2, 3]로 modify됨)

My answer

While문을 돌면서 해당 element가 Array의 맨 마지막에 있는지 확인했다.
맨 마지막이면 살려주고 아니면 splice로 제거.
정렬된 배열이라 다 뭉쳐있을테니 각 뭉치의 제일 오른쪽 애들만 남긴다는 아이디어였다.

var removeDuplicates = function(nums) {
    var count = nums.length - 1;
    while(count >= 0) {
        if(count == nums.lastIndexOf(nums[count])) {
            count--;
        } else {
            nums.splice(count, 1);
        }
    }

    return nums.length;
};

잘 되긴 한다.

성능은 후지다. 이 퍼센트가 뭔가 했더니 하위 5%, 18%더라.

Runtime: 224 ms, faster than 5.75% of JavaScript online submissions for Remove Duplicates from Sorted Array.
Memory Usage: 37.8 MB, less than 18.75% of JavaScript online submissions for Remove Duplicates from Sorted Array.

처음에 param으로 받은 Array를 reference로 고쳐야한단걸 몰랐을때는
Array.prototype.reduce로 접근했다. prev, next를 돌며 앞뒤가 다르면 새로운 Array에 push해줬음. 그건 그것나름대로 제일 앞 or 제일 뒤가 edge case라는 헛점은 있더라 – 무튼 안됨.

다른 사람들은 어케 했는지 보자

Others’ answer

Best practice

var removeDuplicates = function(nums) {
    if (nums.length == 0) return 0;
    var i = 0;
    for (var j = 1; j < nums.length; j++) {
        if (nums[j] != nums[i]) {
            i++;
            nums[i] = nums[j];
        }
    }
    return i + 1;
}

첨엔 이해가 안갔다
이건 [0,0,1,1,1,2,2,3,3,4][ 0, 1, 2, 3, 4, 2, 2, 3, 3, 4 ]로 만들텐데 그럼 뒤에 더러운 숫자들이 남지 않는가?

근데 다시 Question을 읽어보니 뒤에 더러운 숫자가 있던 없던 반환한 lengthNum 길이만큼만 일치하면 되는거더라구.
문제가 여러모로 깔끔하지 못하네…

Answer by @Qfab

var removeDuplicates = function(nums) {
    nums.splice(0, nums.length, ...(new Set(nums)));
};

변태코드

CRA(Create React App)에 tslint, eslint, prettier 적용하기

지금 만드는 토이프로젝트에 tslint, eslint, prettier을 적용한 겸 세팅값을 블로그에도 적어둔다.

CRA로 만든 프로젝트에 따로 webpack config를 eject 하지 않고 위에 3개를 적용할 수 있는 방법임.

Step 1: 온갖 devDependencies를 설치한다.

npm i -D @types/react typescript-eslint/eslint-plugin typescript-eslint/parser eslint eslint-config-prettier eslint-config-react eslint-loader eslint-plugin-prettier prettier tslint typescript

다만 여러분이 이 글을 보는 시점에 https://github.com/prettier/prettier-atom/issues/505#issuecomment-516791742 이 Issue가 해결되지 않았다면 eslint는 5.16.0 버전으로 설치한다(19년 9월 기준으로 v6임)

// eslint를 5.16.0 으로 박아둔 버전
npm i -D @types/react typescript-eslint/eslint-plugin typescript-eslint/parser eslint@5.16.0 eslint-config-prettier eslint-config-react eslint-loader eslint-plugin-prettier prettier tslint typescript

왜냐면 에디터 prettier에서 dependency 에러가 나더라. Failed to load plugin 'prettier' declared in 'CLIOptions': Cannot find module 'eslint-plugin-prettier' 라고 나옴. eslint를 5.16버전으로 다운그레이딩하면 이 에러가 사라진다. 곧 Fix PR 만든다고 했으니 미래에는 에러 해결이 되었길…

내 package.json은 다음과 같다

"devDependencies": {
    "@types/react": "^16.9.2",
    "@typescript-eslint/eslint-plugin": "^2.3.0",
    "@typescript-eslint/parser": "^2.3.0",
    "eslint": "^5.16.0",
    "eslint-config-prettier": "^6.3.0",
    "eslint-config-react": "^1.1.7",
    "eslint-loader": "^3.0.0",
    "eslint-plugin-prettier": "^3.1.1",
    "prettier": "^1.18.2",
    "tslint": "^5.20.0",
    "typescript": "^3.6.3"
  },

Step 2: eslint 셋업을 하는 .eslintrc.json 파일을 만든다

eslint의 세부사항을 셋업할 수 있는 파일을 루트폴더에 생성한다. 잘 보면 타입스크립트와 프리티어 세팅 모두 박혀있다.
.eslintrc.json

{
  "extends": [
    "eslint:recommended",
    "plugin:react/recommended",
    "plugin:@typescript-eslint/recommended",
    "prettier/@typescript-eslint",
    "plugin:prettier/recommended"
  ],
  "plugins": ["react", "@typescript-eslint", "prettier"],
  "env": {
    "browser": true,
    "jasmine": true,
    "jest": true
  },
  "settings": {
    "react": {
      "pragma": "React",
      "version": "detect"
    }
  },
  "parser": "@typescript-eslint/parser"
}

Step 3: 몇몇 파일에 eslint를 disable시킬 .eslintignore 파일을 만든다

서비스워커 파일이나 tests 폴더나 legacy 소스들에는 eslint를 끄고싶은 분들도 있을거다. ignore할 수 있는 파일을 만든다.

.eslintignore

src/registerServiceWorker.js
src/**/__tests__/**

Step 4: 타입스크립트 린트 세팅 파일인 tslint.json을 만든다

TSlint 셋업을 해준다. 요거 키면 .tsx 파일들에 빨간줄이 무지막지하게 나온다.

tslint.json

{
    "defaultSeverity": "error",
    "extends": [
        "tslint:recommended"
    ],
    "jsRules": {},
    "rules": {
      "quotemark": false
    },
    "rulesDirectory": []
}

Step 5: 예쁘게 코드 포매팅을 해주는 프리티어 세팅 파일인 .prettierrc 를 만든다

이렇게 프리티어 세팅을 해주고 VSCode에서 mac기준 shift + option + f를 누르면 세팅값대로 코드를 예쁘게 성형해준다. 입맛대로 세팅을 해준다. 프리티어 다큐멘테이션 참고하삼 https://prettier.io/docs/en/options.html 아래는 제 세팅

.prettierrc

{
  "singleQuote": true,
  "semi": true,
  "useTabs": false,
  "tabWidth": 2,
  "trailingComma": "all",
  "printWidth": 80,
  "arrowParens": "always",
  "orderedImports": true
}

(optional) Step 6: 이제 다했당. package.json에 eslint 바로 고쳐주는 스크립트를 짜둔다

lint:fix 란 이름으로 eslint fix 스크립트를 짜두면 언제든 npm run lint:fix 명령어로 린트 픽스를 할 수 있다. (하지만 난 파일마다 수동으로 단축키를 통해 고치는걸 선호하지)

"scripts": {
    ...
    "lint:fix": "eslint './src/**/*.{ts,tsx}'"
  }

끗!
이제 열시미 js랑 tsx 파일 린트에러를 고치면 됩니다.

적용한 파일은 https://github.com/milooy/TellMe/commit/d2c5520b9d4c0ebfac2629ca2f02066afbeb61b8 참고

[React] External component를 StyledComponent로 감쌌을 때 ‘Warning: Unknown props’ 워닝 해결

Problem

에러가 났을 때 빨간 글자색을 보여주기 위해 StyledComponent에 hasError 프로퍼티를 넘기고

<StyledField hasError={hasError} />

이를 스타일링만 하기 위해 StyledComponent에서만 받아 썼더니

const StyledField = styled(Field)`
  color: ${({ hasError }) => (hasError ? "red" : "black")};
`;

Warning: React does not recognize the errorMessage prop on a DOM element. 에러가 났당. 컴포넌트를 감싼에서만 prop을 쓰고 그 안쪽의 “에서는 errorMessage prop을 안써서 나는 워닝이다.
Screen Shot 2019-09-19 at 4.56.18 PM

Solution

spread operator(...rest)로 hasError를 제외한 나머지 properties만 Field 컴포넌트에 내려보내주면 된다. 코드 드럽네

const StyledField2 = styled(({ hasError, children, ...rest }) => (
  {children}
))`
  color: ${({ hasError }) => (hasError ? "red" : "black")};
`;

Refer

https://github.com/styled-components/styled-components/issues/305

Github Pages로 배포할 폴더 변경하기

결론: subtree를 만들어서 gh-pages브랜치에 원하는 폴더만 올리면 된다.

  1. .gitignore에서 배포 원하는 폴더를 주석처리 (e.g. /public, /dist)
  2. 원하는 폴더를 add하고 commit한다: git add 폴더이름 &amp;&amp; git commit -m "Initial subtree commit"
  3. 서브트리로 gh-pages에 푸시 해준다: git subtree push --prefix 폴더이름 origin gh-pages

두번째 푸시부터 안되는 분들은 아래 3번째 명령어를 써보셔요

  1. git add docs && git commit -m “Subtree commit”
  2. git subtree push –prefix docs origin
  3. git push origin git subtree split --prefix docs master:gh-pages –force

refer: https://gist.github.com/cobyism/4730490