728x90
반응형

해당 에러는 vscode의 typescript와 로컬 typescript의 버전이 맞지 않아서 생긴다.

 

1. vscode의 settings.json 파일에 다음을 추가해준다.

작업 영역의 루트 폴더에서 해야한다. 경로 안의 프로젝트에 typescript를 설치했다면 경로를 인식하지 못한다.

또한 로컬 내에 타입스크립트의 버전과 vscode 타입스크립트의 버전을 꼭 확인해야한다.

{
	"typescript.tsdk": "node_modules/typescript/lib"
}

그 다음 vscode를 껐다 키고 f1을 누르면

이렇게 나오는데, 두 번째 작업 영역 버전을 사용하면 된다.

728x90
반응형
728x90
반응형

기존 js로 되어있던 프로젝트를 typescript로 변경해야 될 때가 있다.

 

1. 필요한 패키지 다운로드

$ npm i typescript ts-loader @types/node @types/react @types/react-dom @types/jest --dev

2. tsc 명령어 안먹힘

window로 작업하던 중 tsc 명령어가 안 먹히는 것을 보고 해결법을 찾았다. 아래와 같은 오류일 때 가능하다.

tsc : 'tsc' 용어가 cmdlet, 함수, 스크립트 파일 또는 실행할 수 있는 프로그램 이름으로 인식되지 않습니다. 
 이름이 정확한지 확인하고 경로가 포함된 경우 경로가 올바른지 검증한 다음 다시 시도하십시오.

 

window 파워 셀을 관리자 권한으로 실행한 뒤 권한을 RemoteSigned로 바꿔준다.

 

3. tsconfig.json 파일 생성

tsc --init 명령어로 tsconfig.json 파일을 만든 뒤에 다음과 같이 작성한다. 옵션을 꼭 따라할 필요는 없다.

{
  "compileOnSave": true,
  "compilerOptions": {
    "target": "es2016",
    "jsx": "react-jsx",
    "module": "esnext",
    "sourceMap": true,
    "removeComments": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "strict": true,
    "skipLibCheck": true,
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "allowSyntheticDefaultImports": true,
    "noFallthroughCasesInSwitch": true,
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": false
  },
  "include": [
    "./src/*"
  ],
  "exclude": [
    "node_modules/*"
  ]
}

 

4. webpack.config.js

const path = require('path');

module.exports = {
  entry: './src/index.ts',
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        use: 'ts-loader',
        exclude: /node_modules/,
      },
    ],
  },
  resolve: {
    extensions: ['.tsx', '.ts', '.js'],
  },
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist'),
  },
};

기존 webpack 파일에 필요한 부분을 채워넣어준다.

 

혹시 기존에 babel 을 사용하고 있었다면 .babelrc 파일에 아래를 추가하고

"preset" : ["@babel/preset-typescript"]

webpack 파일에 다음을 추가해주자.

      {
        test: /\.(ts|js)x?$/,
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
        },
      },

 

4. 컴파일

$ tsc

 

혹시 컴파일 시 결과를 터미널에서 알고 싶을 때는 tsconfig.json 폴더에서 noemit 부분을 false로 바꿔준다.

컴파일 하고 Cannot write file '경로' because it would overwrite input file.

이런 에러가 뜬다면

{
  "compilerOptions": {
    "outDir": "build",
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "build/**/*"]
}

outDir 폴더를 만들어주고, exclude 시켜준다.

 

tsc 명령어로 에러가 안뜬다면 webpack을 실행해준다.

$ npx webpack

 

참고로 tsc 다음에 파일 명을 쓴다면 tsconfig.json이 안먹힌다!

5. can only be default-imported using the 'esModuleInterop' flag

위와 같은 에러가 뜬다면 tsconfig.json 파일에 "esModuleInterop": true, 속성을 추가해주자.

기존 CommonJS 모듈을 ES6모듈 사양을 준수하여 가져올 수 있게 된다.

728x90
반응형
728x90
반응형

개요

React 로 개발을 하면서 프론트 서버가 가끔 강제 종료되는 일이 자주 발생했다.
JavaScript heap out of memory 라고 오류 메세지가 출력 되는데
이유를 살펴보니 node.js가 과도하게 메모리 점유를 해서 발생한다.
해결 방법으로 더 큰 메모리를 할당 해 주면 된다고 하여 8GB를 할당 해 주었다.

해결 1

할당 해주는 방법은
터미널에

export NODE_OPTIONS="--max-old-space-size=8192"

위 코드를 입력해주면 해결 된다.

하지만 대부분 1시간을 버티지 못하도 다시 서버가 강제 종료 되었다.

알고 보니 너무 많이 할당을 해주어도 문제이다.

내 노트북은 8gb 램인데 다 할당을 해주니 다른 프로그램이 할당 받을 것을 다 뺏어버린 것이다.
결국 충돌로 꺼지게 된다는것을 알게 되었다.
과유 불급이었다.

해결 2

그래서 1gb부터 8gb까지 1기가씩 증가시켜서 램을 할당 해주니 3gb가 딱 적당했다.
export NODE_OPTIONS="--max-old-space-size=3072"

나는 이 오류로 2달을 고생했다. 지금이라도 고쳐서 다행이다.
구글링으로 알기 어려우니 글을 남겨서 다른 사람들도 램을 적당히 할당해주길 바란다.

1gb ~ 8gb

1GB ~ 8GB 할당 명령어

#1gb
export NODE_OPTIONS="--max-old-space-size=1024"

#2gb
export NODE_OPTIONS="--max-old-space-size=2048"

#3gb
export NODE_OPTIONS="--max-old-space-size=3072"

#4gb
export NODE_OPTIONS="--max-old-space-size=4096"

#5gb
export NODE_OPTIONS="--max-old-space-size=5120"

#6gb
export NODE_OPTIONS="--max-old-space-size=6144"

#7gb
export NODE_OPTIONS="--max-old-space-size=7168"

#8gb 
export NODE_OPTIONS="--max-old-space-size=8192"

8gb 이상 할당은 해주지 말자.
gb계산이 귀찮으니 위 코드를 복붙해서 사용하길 바란다.

etc

CRA가 아닌 node에서 발생해도 해결이 가능하다.

 
728x90
반응형
728x90
반응형

React에서는 줄바꿈을 허용하지 않는다. 때문에 매핑하고 <br /> 태그를 임의로 주어서 줄바꿈을 표기해주자.

 

<Wrap ai={`start`} margin={`25px 0 0 0`}>
                {state.post_content.split("\n").map((line: any) => { //this.props.data.content: 내용
                  return (
                    <span>
                      {line}
                      <br />
                    </span>
                  );
                })}
              </Wrap>

 

728x90
반응형
728x90
반응형
// 스크롤이 50px 이상 내려올경우 true값을 넣어줄 useState
const [scroll, setScroll] = useState(false);

useEffect(() => {
    window.addEventListener('scroll', handleScroll);
    return () => {
      window.removeEventListener('scroll', handleScroll); //clean up
    };
  }, []);

const handleScroll = () => {
	console.log("window.scrollY : ", window.scrollY)
  };

 

기준점을 잡고 현재 상태에서 올라갔는지 내려갔는지를 보려면 state가 아닌 일반 변수를 써야한다.

var scroll = 0;
    useEffect(() => {
        window.addEventListener('scroll', () => {
            // 검색등을 한 뒤 스크롤이 맨 위일 때는 임의로 컴포넌트를 보여주게 함.
            if (window.scrollY === 0) {
                dispatch({ name: "scrollUp", value: true })
            }
            // 스크롤이 맨 마지막에 도달했을 때
            else {
                if (Math.round(document.documentElement.scrollTop + window.innerHeight) - document.body.scrollHeight > -10) {
                    dispatch({ name: "scrollUp", value: false });
                }
                else if ((window.scrollY) < 10) {
                    dispatch({ name: "scrollUp", value: true });
                }
                else {
                    if (scroll < window.scrollY) {
                        dispatch({ name: "scrollUp", value: false });
                    }
                    else {
                        dispatch({ name: "scrollUp", value: true });
                    }
                }
            }

            scroll = window.scrollY;
        });
    }, []);
728x90
반응형
728x90
반응형

아래와 같은 방법을 쓰면 사용할 수 있다.

class App extends React.Component {

  
  render() {
  let codes = "<b>Will This Work?</b>";
    return (
      <div dangerouslySetInnerHTML={ {__html: codes} }>
      </div>
    );
  }
};
728x90
반응형
728x90
반응형
 
useEffect(() => {
function handleClickOutside(event: MouseEvent) {
if (barRef.current && !barRef.current.contains(event.target as Node)) {
setBarOpen(false);
}
}
if (barOpen) {
document.addEventListener('mousedown', handleClickOutside);
return () => {
document.removeEventListener('mousedown', handleClickOutside);
};
}
}, [barRef])
728x90
반응형
728x90
반응형

xlsx 모듈 설치

$npm install xlsx

 

@breif xlsx 모듈추출

const xlsx = require( "xlsx" );

 

@breif 가상의 엑셀파일을 생성

const book = xlsx.utils.book_new();

 

 

 

첫번째 방법 (aoa_to_sheet)

const doctors = xlsx.utils.aoa_to_sheet( [

      [ "학과", "직급", "이름", "나이" ]

    , [ "흉부외과", "병원장", "주전", "67" ]

    , [ "흉부외과", "교수", "천명태", "52" ]

    , [ "흉부외과", "치프", "도재학", "39" ]

    , [ "소아외과", "레지던트", "장겨울", "29" ]

    , [ "산부인과", "레지던트", "추민하", "34" ]

    , [ "산부인과", "레지던트", "명은원", "28" ]

    , [ "신경외과", "교수", "민기준", "55" ]

    , [ "신경외과", "치프", "용석민", "33" ]

    , [ "신경외과", "레지던트", "안치홍", "38" ]

    , [ "신경외과", "레지던트", "허선빈", "31" ]

    , [ "응급의학과", "조교수", "봉광현", "40" ]

    , [ "응급의학과", "펠로우", "배준희", "31" ]

] );

 

넓이 지정

doctors["!cols"] = [

      { wpx : 130 }   // A열

    , { wpx : 100 }   // B열

    , { wpx : 80 }    // C열

    , { wch : 60 }    // D열

]

 

xlsx.utils.book_append_sheet( book, doctors, "DOCTOR" );

 


 

두번째 방법 (json_to_sheet)

const nurses = xlsx.utils.json_to_sheet( [

      { A : "학과", B : "직급", C : "이름", D : "나이" }

    , { A : "흉부외과", B : "PA간호사", C : "소이현", D : "33" }

    , { A : "소아외과", B : "PA간호사", C : "한현희", D : "29" }

    , { A : "산부인과", B : "분만실간호사", C : "한한승주현희", D : "41" }

    , { A : "산부인과", B : "PA간호사", C : "은선진", D : "36" }

    , { A : "간담췌외과", B : "수간호사", C : "송수빈", D : "45" }

    , { A : "간담췌외과", B : "병동간호사", C : "이영하", D : "35" }

    , { A : "간담췌외과", B : "병동간호사", C : "김재환", D : "28" }

    , { A : "간담췌외과", B : "PA간호사", C : "국해성", D : "32" }

    , { A : "간담췌외과", B : "이식코디네이터", C : "함덕주", D : "37" }

    , { A : "신경외과", B : "PA간호사", C : "황재신", D : "39" }

    , { A : "응급의학과", B : "응급실간호사", C : "선우희수", D : "26" }

], { header : ["A", "B", "C", "D"], skipHeader : true } );

 

넓이 지정

nurses["!cols"] = [

      { wpx : 130 }   // A열

    , { wpx : 100 }   // B열

    , { wpx : 80 }    // C열

    , { wch : 60 }    // D열

]

xlsx.utils.book_append_sheet( book, nurses, "NURSES" );

 

 


마지막 엑셀파일을 생성하고 저장한다.

xlsx.writeFile( book, "dramatis_personae.xlsx" ); 

728x90
반응형
728x90
반응형

React에서 ES8 문법인 async/await를 사용해 비동기 함수를 작성하면 브라우저에서 다음과 같은 에러가 발생한다.

 

ReferenceError: regeneratorRuntime is not defined

 

 

babel 7.4.0부터는 core-js/stable(ECMAScript 기능들의 polyfill 제공)과 regenerator-runtime/runtime (transpiled generator functions 사용을 위해 필요) 직접 포함하면서 @babel/polyfill이 deprecated되었다.

 

때문에 아래와 같이 문제를 해결하겠다.

 

1. 먼저 관련된 babel들을 설치해주고,

$ npm install --save-dev @babel/plugin-transform-runtime
$ npm install --save @babel/runtime

 

2. babel 설정에 plugin을 등록해주자.

{
  "plugins": ["@babel/plugin-transform-runtime"]
}
728x90
반응형
728x90
반응형

캘린더를 다루는 모듈 중 react-day-picker라는 모듈이 있다. 

해당 날짜를 클릭했을 때의 이벤트를 주고 싶다면 한 번 도전해보자.

 

먼저 react 앱과 react-day-picker를 설치한다.

 

$ npx create-react-app teepo
$ npm install react-day-picker --save

 

$ npm i react-day-picker

 

그 다음 App.js 를 다음과 같이 수정하고 실행해본다.

 

App.js

import './App.css';
import DayPicker from 'react-day-picker';
import 'react-day-picker/lib/style.css';

function App() {
  return (
    <div className="App">
      <DayPicker />
    </div>
  );
}

export default App;

 

 

이렇게 달력이 잘 뜨는 것을 확인할 수 있다.

그럼 이번에는 onDayClick()을 통해 날짜를 선택할 때 하단에 해당 날짜가 출력되게끔 수정해보자.

 

App.js

import './App.css';
import { useState } from 'react'
import DayPicker from 'react-day-picker';
import 'react-day-picker/lib/style.css';

function App() {

  const [day,setDay] = useState();

  const handleDayClick = (day) => {
    setDay(day);
  }

  return (
    <div className="App">
      <DayPicker onDayClick={handleDayClick} />
      {day ? <p>{day.toString()}</p> : <p>날짜를 선택해주세요</p>}
    </div>
  );
}

export default App;

 

 

여기서 DayPicker에 selectedDays() 메소드를 추가하면 선택한 날짜에 표시를 할 수 있다.

 

App.js

import './App.css';
import { useState } from 'react'
import DayPicker from 'react-day-picker';
import 'react-day-picker/lib/style.css';

function App() {

  const [day,setDay] = useState();

  const handleDayClick = (day) => {
    setDay(day);
  }

  return (
    <div className="App">
      <DayPicker
        onDayClick={handleDayClick}
        selectedDays={day}/>
      {day ? <p>{day.toString()}</p> : <p>날짜를 선택해주세요</p>}
    </div>
  );
}

export default App;

 

 

HandleDayClick의 두번째 파라미터에 selected를 사용하면 이미 선택된 날짜를 취소할 수도 있다.

 

App.js

import './App.css';
import { useState } from 'react'
import DayPicker from 'react-day-picker';
import 'react-day-picker/lib/style.css';

function App() {

  const [day, setDay] = useState();
  const [selectDay, setSelectDay] = useState(false);

  const handleDayClick = (day, { selected }) => {
    if (selected) {
      setDay(undefined);
    }
    else {
      setDay(day)
    }
  }

  return (
    <div className="App">
      <DayPicker
        onDayClick={handleDayClick}
        selectedDays={day} />
      {day ? <p>{day.toString()}</p> : <p>날짜를 선택해주세요</p>}
      
    </div>
  );
}

export default App;

 

728x90
반응형

+ Recent posts