React.js로 개발을 하다 절대 경로 설정을 추가하게 되었다. TypeScript의 경우 tsconfig.json 파일을, JavaScript의 경우 jsconfig.json 파일만 추가하면 되었기 때문에 그리 어렵지 않게 설정할 수 있었다.

 

하지만 문제는 절대 경로를 추가하니 eslint에서 문법이 이상하다고 계속 경고를 울렸다.

 

이 이슈도 좀 유명한 이슈였는지 검색하니 여러 가지 방법이 나왔고, 여러 방법을 시도하던 중 eslint에서 'import/no-unresolved' 옵션을 아래와 같이 설정해주면 된다고 하여 이 이슈도 해결할 수 있었다.

"rules": {
   "import/no-unresolved": [
      2, 
      { "caseSensitive": false }
   ],
   // 또는
    "import/no-unresolved": "off",
}

 

나 같은 경우 다른 설정은 작동하지 않아 "off"로 해결할 수 있었는데, 이 문제를 해결하는 글들을 읽어보며 "import/no-unresolved"가 정확히 어떤 옵션인지는 설명해주지 않아 나의 호기심을 자극했다.

 

다행히 GitHub에 이에 관련된 글이 있어, 이 부분을 알 수 있게 되었다. 아래 링크를 첨부하겠다.

https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-unresolved.md

 

원글을 읽는 것이 가장 좋겠지만, 시간이 없거나 영어를 잘 못 읽는 분들을 위해 간단히 정리하자면

 

경로의 파일이 unresolved하는 일이 없도록 하는 옵션인 것 같다. 그래서 이름부터 import/no-unresolved다. 정확히는 import로 가져온 파일 혹은 모듈이 unresolved가 되지 않도록(no)하는 옵션이다.

 

친절한 이 옵션은 import 뿐만 아니라 require, define 등의 CommonJS 혹은 AMD도 지원을 해준다.

심지어 CommonJS 혹은 AMD를 { commonjs: true/false, amd: true/false } 옵션을 통하여 감지할지 말지를 정해줄 수도 있다!

 

그리고 한 가지 옵션을 더 설명하자면 "caseSensitive"라는 옵션이 있는데, 파일 경로가 틀린 것을 감지하는 옵션이다.

당연히 기본적으로는 켜져있어서 true이고, 끄고 싶다면 false로 바꾸어주면 된다.

절대 경로의 경우에는 flie system의 실제 경로와 맞지 않기 때문에 lint에서 빨간 밑줄을 띄우게 되고, 이 옵션을 끄게되면 이제 더이상 실제 경로와 틀리다는 경고성 밑줄이 뜨게 되지 않는 것이다.

 

그리고 또 여러 가지 옵션이 더 있는데, 자세한 사항은 위의 GitHub 링크 들어가서 읽어보면 좋을 것 같다.

 

다시 한번 더 링크

https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-unresolved.md

반응형

의문의 시작

- 개발을 하던 도중, 이 글의 제목과 같은 의문이 생겼다.

- 이 의문이 무엇인지에 대하 간단히 설명하자면 useEffect, useCallback, useMemo, useLayoutoff 같은 hook은 인자로 callback 함수와 deps를 받는다. 이 때 deps에 넣은 값이 변경되면 callback을 다시 실행한다.

- hook의 사용법이나 어떻게 동작하는지 알고 싶다면 관련된 다른 글을 보거나, 아래의 공식 문서를 읽는 것이 도움이 될 것이다.

https://ko.reactjs.org/docs/hooks-reference.html

 

- 다시 본론으로 돌아가, 이런 의문이 생긴 이유는 hook의 deps에 object를 넣는 일이 생겼다. object를 넣었을때는 어떤 경우에 콜백 함수가 실행될까라는 의문이 들었다. object 내부의 프로퍼티가 바뀌었을때도 감지해서 콜백 함수가 실행될까? 혹은 key, value가 같은 object로 바뀌었을때는 콜백함수가 실행될까라는 의문이 들었다.

- 결론적으로 설명하면, objectA !== objectB가 성립되면 콜백 함수가 실행되었다. 즉 내부의 프로퍼티 변경을 감지하는 것이 아닌 단순히 객체의 주소 값만을 비교하고 달라지면 콜백 함수를 실행하는 것이였다.

- 따라서 당연한 이야기겠지만, 테스트를 해 보았을때 objectState의 프로퍼티를 변경하거나, 프로퍼티를 변경한 후 그 객체를 다시 setState 해줘도 콜백함수는 실행되지 않았다.

 

동작 원리

- 물론 여기까지만 봐도 짐작으로 deps의 변화를 어떻게 감지하는지 유추가 되지만, 정확히 어떻게 돌아가는지 확인하고 싶어서 찾아보기 시작했다. 처음에는 TypeScript에 정의된 deps의 타입을 찾아보았다. deps의 타입은 dependencyList라고 나오고 배열 안에 값이 들어가는 것만 확인할 수 있었다.

- 그 다음으로 찾아본 것은 React의 GitHub 코드를 찾아보았지만 너무 방대한 나머지 처음에는 찾다 포기를 하였다.

- 이에 관련된 글이 있을까 싶어 찾아보다가 믿음직하고 설명도 잘 되어 있는 글을 찾았다. 바로 netlify의 기술 블로그?였다.

https://www.netlify.com/blog/2019/03/11/deep-dive-how-do-react-hooks-really-work/

 

- 또한 이 글을 읽고 다시 React 공식 GitHub를 찾아보니 deps의 동작 부분을 확인하고 이해할 수 있었다.

 

- 결론적으로 얻은 결론은 단순히 새로운 deps 배열과 기존 deps 배열을 for문으로 돌면서 값을 하나하나 비교해서 값이 하나라도 다르다면 콜백 함수를 실행시켜주는 식이였다.

- 그 비교는 단순히 a===b를 통한 비교였고, 따라서 오브젝트의 프로퍼티가 달라지면 그 부분은 확인할 수 없었다.

- 물론 React에서는 불변성을 지키기 위해 오브젝트의 프로퍼티를 바꿀 때는 새로운 오브젝트를 생성하기 때문에 대부분의 경우 이 부분이 문제가 되지는 않을 것이다.

 

- React 공식 GitHub에서 이러한 동작을 여러 부분에서 확인할 수 있지만, 가장 쉽게 이해할 수 있는 부분은 아마 이 부분인 것 같다.

https://github.com/facebook/react/blob/149b420f63903bcfb99455337a376c75384f86af/packages/react-devtools-shared/src/backend/renderer.js#L1378

반응형

<읽기 전 주의> 이 글은 외국 블로그를 퍼온 문익점 글입니다. 읽은 블로그가 틀린 내용을 담고 있다면 이 내용도 틀릴 수 있습니다!

- 출처

https://hackernoon.com/why-import-react-from-react-in-a-functional-component-657aed821f7a

글쓰면서 공식 문서도 참고했으니 틀릴 가능성은 낮을 것 같다... 물론 영어를 잘못 읽었거나 내용을 잘못 이해했다면 틀렸을 가능성도 있으니 출처도 한 번씩 들어가 읽는 걸 추천한다.

 

궁금해진 이유

- 토이프로젝트를 하기 위해 lint 설정을 처음부터 다시 할 일이 있었는데, lint 설정을 마치니  'React' must be in scope when using JSX 라는 오류가 떴다.

- 이 오류의 원인을 찾아보니 컴포넌트 파일(.jsx) 안에 import React from 'react' 가 빠져있어서 발생하는 오류라고 했다.

- 오류를 보니, 저 줄을 왜 함수형 컴포넌트에는 항상 넣을까라는 궁금증이 들었다. 심지어 이 줄이 없어도 문제 없이 돌아가기는 한다.

- 그래서 이유를 찾아봤고, 이에 대해 정리된 블로그가 있어 번역 및 정리해보았다.

 

이슈의 원인

- 원인은 바로 BABEL과 JSX이다.

 

- JSX 엘리먼트는 단지 React.createElement()를 호출하는 편리한 문법에 불과하다.

(공식문서 참조 : https://ko.reactjs.org/docs/react-api.html#creating-react-elements)

 

- 따라서 BABEL로 JSX인 함수형 컴포넌트를 트랜스파일링하면 React.createElement를 이용한 코드로 변경된다. 그렇기 때문에 React.createElement를 호출하기 위하여 React가 필요한 것이다.

 

그런데 안써도 된다?

- 하지만 React 17부터는 안써도 된다. 왜냐면 새로운 방법의 JSX 변환을 사용하기 때문이다.

 

관련 내용 블로그 : https://dev.to/titungdup/you-no-longer-need-to-import-react-from-react-3pbj

공식 문서 : https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html

 

- 따라서 쓰기 귀찮으신 분은 lint 설정을 변경하여 에러를 무시하도록 한 후 React 17 혹은 그 이후의 버젼을 사용하면 된다.

 

 

 

 

 

마지막으로 다시 한 번 출처

https://hackernoon.com/why-import-react-from-react-in-a-functional-component-657aed821f7a

https://ko.reactjs.org/docs/react-api.html#creating-react-elements

https://dev.to/titungdup/you-no-longer-need-to-import-react-from-react-3pbj

https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html

 

 

반응형

Error: Could not find a valid build in the '/Users/이름/폴더/폴더이름/.next' directory! Try building your app with 'next build' before starting the server.

 

오류 스크린 샷

next dev나 next start 명령어를 쳤을 때, 실행이 안될 경우 문제 해결 방법이다.

 

문제 해결 방법은 간단하다.

 

next build 명령어를 입력 후, next dev를 하면 된다.

 

어려운 문제는 아니고, 먼저 빌드를 해놓아야 실행가능한다고 한다.

 

사실 오류 창만 잘 읽으면 해결할 문제이다.

 

요즘 프레임워크나 라이브러리는 친절해서 오류 문구만 잘 읽어도 50프로 이상은 잘 해결되는 것 같다.

반응형

Lodash의 Debounce를 공부하다가, 정말 어이가 없는 경우가 있어서 하루 종일 무엇이 문제일까 고민하다가,

 

드디어 원인을 알아냈다!

 

문제는 이렇다

 

정상

먼저 내가 어떤 것을 만드려고 했는지 설명하겠다.

 

현재 만든 것은 이름을 입력하면, axios로 api에서 가져온 이름 데이터 중, Family Name, 즉 성이 같은 이름들을 뽑아내는 것이다.

이럴 때, 검색 창에서 이름을 입력할 때마다 계속 데이터를 요청하면 서버에 과부하를 가져다 줄 수 있다.

 

예를 들면 김길동을 검색할 때, ㄱ -> 기 -> 김 -> 김ㄱ ->  김기 -> 김길  이런 순으로 나아갈텐데, 이렇게 변화할 때마다,

서버에 계속해서 에 맞는 데이터 가져와! 에 맞는 데이터 가져와! 에 맞는 데이터 가져와! 김ㄱ에서 에 맞는 데이터 가져와!

 

이렇게 계속 요청한다. 이것은 서버에 요청도 문제지만, 렌더링 같은 프론트 쪽에서도 오버헤드가 커지게 된다.

 

이런 경우를 방지하기 위해 방법을 생각해봤는데,

내가 처음에 생각한 방법은 ,useEffect를 사용하는 방법이었다.

useEffect를 사용한 방법

검색어에 입력된 정보를 문자열 변수에 저장한 후, 문자열의 첫번째 값이 바뀔 때만 데이터를 서버에 요청하는 방식이었다.

 

이 방법도 잘 작동했지만, debounce delay라는 방법이 있고, 실제로 이 방법을 많이 사용한다하여 공부해보았다.

 

Lodash라는 라이브러리에서 제공하는 함수인데, ㄱ -> 기 -> 김 -> 김ㄱ ->  김기 -> 김길 이렇게 진행되며 요청을 할 때, 계속해서 요청을 보내는 것이 아니라, 값이 바뀔 때는 가만히 있다가, 값이 바뀌지 않을 때 마지막 요청, 마지막 이벤트에 대한 함수의 결과 값만 반환하는 방식이었다.

 

그래서 debounce delay라는 방식은 값이 바뀌지 않을 때, 이벤트가 더 이상 일어나지 않은 후 얼마 간의 딜레이 후에 작동을 하는 방식이다.

이에 대한 설명은 

https://frontcode.tistory.com/60

 

[REACT] React SyntheticEvent

React SyntheticEvent GetInputData = event => { this.setState({ [event.target.name]: event.target.value }); }; GetInputData(event)} />; ReactJS를 공부하고 여러 프로젝트를 진행해보며 나의 코딩 능력이..

frontcode.tistory.com

이 블로그를 참고해보는 것이 좋을 것 같다. 여기 글에서는 일단 오류 해결을 중점적으로 작성할 예정이다.

 

 

그래서 코드를

지역 변수

이렇게 작성했을 때는 매우 잘 작동하였다. 

 

하지만 inputData를 useState를 사용하여 state에 저장하여 코드를 작성하면 이렇게

오류...ㅠㅠ

 

왜이럴까

딜레이가 있긴한데, 일정 딜레이 이후에 9번 변화가 있었다면 9번을 데이터 요청을 주르르륵한다.

 

아마 원인은 state의 값이 바뀔 때마다 리렌더링 되는데, 이때마다 함수가 새롭게 호출이 되어 문제가 발생하는 것 같다.

하하 렌더링 로그

실제로 컴포넌트 내에 이런 "하하"라는 로그를 찍어서 확인해보면, state 값이 변경될 때마다 렌더링이 엄청나게 발생하는 것을 볼 수 있다.

 

그럼 이 문제를 어떻게 해결할 것인가?

state를 사용하지 않는 방법이 있지만, 이것은 근본적인 해결책이 되지 못한다.

 

그래서

해결법

이렇게 setInputData를 debounce Delay 함수에 넣어주면 문제가 해결된다.

 

하지만 이렇게 되면 비동기적으로 진행되는 JavaScript의 특성상,

fetchData가 먼저 실행되서 InputData가 바뀐 것이 반영되지 않을 수 있다.

 

이 부분만 고려해주면 문제 끝!!

 

많이 부족하지만 코드를 올려본다

https://github.com/puba5/MatZipJokBo/blob/master/pages/axiosTest.js

 

puba5/MatZipJokBo

홍대 맛집족보 페이지. Contribute to puba5/MatZipJokBo development by creating an account on GitHub.

github.com

 

 

반응형

* 간단 정리

 

State와 Event가 있다.

 

Event가 실행될 때 State의 값을 만지려면, 직접 건드리지 못하므로

 

Action을 만들고, 그것들 Dispatch(실행)해야한다.

 

Action을 어떻게 처리할지는 Reducer에서 관리를 한다.

 

State를 어떻게 바꿀지는 reducer에 기록한다.

 

---------------------------------------------------------------------------

 

사실 이 부분은 어떤 것인지 잘 몰라서 공부를 해보고 좀 더 익숙해져야하는데,

 

써보다가 setState와 비슷한 것 같아서 찾아보니 비슷한 역할을 하는 것이 맞다.

 

하지만 reduce는 Vuex ( 아직 redux를 안써봐서... ) 처럼 좀 더 중간에서 관리한다는 느낌이고,

 

setState는 단순 변수나 배열 같은 걸 관리하기 좋다면

 

reduce는 object를 관리하기 좋다고 한다.

 

많이 써봐서 손에 익혀봐야겠다.

반응형

hook을 사용했을 경우를 가정했다.

 

 

1.  npm install react-ga --save 으로 react-ga를 React 프로젝트에 설치한다.

 

2. 체크하고자하는 페이지에

 

import ReactGA from "react-ga"

 

 

export default function Home() {

 

useEffect(() => {

getGA();

}, []);

 

const getGA = () => {

console.log("페이지 들어옴");

const pathName = window.location.pathname;

ReactGA.initialize("UA-로 시작하는 값");

ReactGA.set({ page: pathName });

ReactGA.pageview(pathName);

};

 

return <wrapper/>;

 

}

 

이런 식으로 해주면 된다.

 

useEffect 안에 이렇게 함수화시켜서 넣어주지 않으면,

주소를 받기 전에 window.location.pathname를 찾는 경우가 생겨 오류가 발생했다.

window가 존재하지 않는다고 ㅠ

 

사실 hook을 사용할 때 이 오류 알려주는 글이 없어서 작성해보았다.

 

 

만약 이래도 안된다면 

import Router from "next/router";

를 추가해보아라...

반응형

별로 어려운 것은 아니지만, 찾아보니 잘 적힌 설명이 없어서 간략하게 적어보려한다.

 

먼저 json 파일을 만든다.

 

 

a.json 

 

{

 “hello”: [

    {

      "id": 0,

      "content": “없어”

    },

    {

      "id": 1,

      "content": “있어”

    },

]

}

 

그리고 json 파일을 읽어올 js 파일에 이 json 파일을 import한다

 

import AA from “a.json 파일의 경로”

 

그 후, json 파일을 사용하듯 사용하면 된다.

 

예를 들면 “없어”를 출력해주고 싶다면

 

console.log(AA.hello[0].content)

 

이런식으로 말이다.

반응형

+ Recent posts