210602 Infinite scrolling과 Virtualized list

infinite scroll과 virtualized list

Infinite scrolling 구현

Infinite scrolling을 구현하기 위해 스크롤이 가장 최 하단으로 이동했을때 이벤트를 발생시켜야 한다.
실제 실무에서는 이벤트 발생시점이 최하단이 아닌 하단에서 일정 px 떨어진 이전 시점에 미리 로드할 데이터를 로딩시켜 사용자가 스크롤링을 했을때 끊기는 느낌이 들지 않도록 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
useEffect(() => {
// 현재 스크롤 위치
function onScroll() {
// 스크롤된 높이를 구하는데 아래 세가지 함수가 많이 쓰인다.
console.log(
// (1) 얼마나 내렸는지
// 가장 최하단으로 스크롤을 내리면, 최 하단으로 내려간 페이지의 최 상단이 마지막 내려간 지점이 된다.
window.scrollY,

// (2) 화면에 보이는 길이(최상단에서 하단 스크롤 위까지 길이)
document.documentElement.clientHeight,

// (3) 총 길이 (스크롤의 제일 위부터 아래까지 총 길이)
// (=) window.scrollY + document.documentElement.clientHeight
document.documentElement.scrollHeight

// (1)과 (2)의 합이 (3)과 같을때 스크롤이 가장 최 하단으로 내려갔다는 것을 의미한다.
// 이 시점에 새로 로딩
);
// 끝에서 300px 위보다 더 많이 내렸을때
if (
window.scrollY + document.documentElement.clientHeight >
document.documentElement.scrollHeight - 300
) {
// loadPostLoading이 false인 경우에만 새로운 요청을 한다.
if (hasMorePosts && !loadPostLoading) {
dispatch({
type: LOAD_POST_REQUEST,
data: mainPosts[mainPosts.length - 1].id
});
}
}
}

window.addEventListener('scroll', onScroll);

// 반드시 스크롤했떤 이벤트를 해제시켜줘야 한다.
// 안그러면 메모리상에 계속 남아있다.
return () => {
window.removeEventListener('scroll', onScroll);
};
}, [hasMorePosts, mainPosts, loadPostLoading]);

throttle과 takelatest

infinite scrolling을 구현하면서 scroll이벤트가 발생할때마다 매번 비동기 요청이 발생을 하였는데, 이 문제를 해결하기 위해 throttle과 takelatest를 사용해서 해결해보려고 했다.
하지만 throttle과 takelatest 모두 요청(Async request)은 차단되지 않고, 응답(Response)만을 차단하기 때문에 만약에 5s 간격으로 throttle 처리를 하게 되면, 받은 요청에 대해서는 취소되지 않고, 5s 간격으로 지연되서 처리가 되는 것을 확인할 수 있었다.

본질적으로 해결하고자 하는 것은 scroll이벤트에서 발생되는 요청 자체를 차단하는 것이기 때문에 이 문제 해결을 위해 redux의 상태 데이터에서 해당 비동기 처리 요청에 대한 loading과 관련된 상태값을 활용하여 해결하였다.

Read more

210601 faker를 사용해서 dummy data 만들기, placeholder.com, Redux toolkit

faker

faker

개발을 하다보면 임의로 데이터를 넣어 실제 페이지가 어떻게 출력이 되는지 확인해야될 때가 있다.
소수의 데이터는 괜찮지만 10개 이상의 데이터를 넣어서 확인을 해야 될 때에는 여간 번거로운 일이 아니다.
이런 경우에 facker라는 패키지를 사용해서 임의의 dummy 데이터를 넣어 줄 수 있다.
(무한 스크롤링 테스트)

[참고]: https://www.npmjs.com/package/faker

1
$ npm i faker

Placeholder.com

dummy 이미지 대체하여 사용할 수 있다.

[참고] : https://placeholder.com/

Redux toolkit

createReducer, createAction을 사용해서 Redux를 사용할때 코드가 길어지는 것을 보완할 수 있다.

이전에 공부할때 정리한 내용을 참고하자.

http://localhost:4000/2021/04/30/202104/210430-Redux_TIL/

210526 immer

immer

immer

state의 데이터 구조가 복잡해지면 불변성을 지키기 위해 변하지 않는 값에 대해 spread 문법을 사용해서 얕은 복사를 하는 것이 지저분해질 수 있는데 immer를 사용하면 이 문제를 해결할 수 있다.

1
$ npm i immer

Redux에서만 아니라 React의 useState, setState에서도 immer를 사용할 수 있으며,hooks를 위한 useImmer도 있다.(useState 대체 가능)

우선 Redux의 reducer 함수에서의 immer의 사용에 대해서 알아보자.

reducer함수는 이전 상태를 action을 통해 다음 상태로 만들어내는 역할을 한다.
이때 새로운 상태는 반드시 불변성을 지켜서 구현을 해줘야 하는데, 구조가 복잡한 객체의 불변성을 지켜서 상태값을 업데이트하는 것이 복잡한 경우에는 immer를 사용한다.

immer의 기본 사용 형태
기존 reducer함수의 switch-case 문을 produce의 내부에 작성해준다.

1
2
3
const reducer = (state = initialState, action) => {
return produce(state, (draft) => {});
};

immer를 사용하게 되면, 기존에 state로 작성했던 부분이 draft로 대체가 된다. draft는 별도의 불변성과 상관없이 작성을 해줘도 immer가 알아서 새로운 state를 불변성 지켜서 만들어준다. (state 인자는 건들이지 말고 draft만 조작하도록 한다 - return produce()부분이 불변성을 지킨 새로운 state 값을 반환해준다)

Read more

210525 React eslint 설정, shortid

 React eslint 설정

React ESLint

ESLint는 자바스크립트 문법 중에 에러가 있는 곳에 표시를 해주는 도구이다. 개발자가 직접 정의한 내용대로 코드를 점검하고 에러가 있으면 코드에 직접 표시를 해주기 때문에 매우 편리하며, 문법 에러뿐만 아니라 다른 개발자들과 협업을 할때 코딩 스타일을 정할 수 있어 매우 유용하다.

Read more

210516 ReactJS TIL - 컴포넌트 폴더 구조, 해쉬태그 구현을 위한 정규표현식

React

컴포넌트 폴더 구조

컴포넌트를 작성할때 각각의 개별 컴포넌트를 하나의 개별 폴더로 분리해서 작성해주는 것이 좋다.
그 이유는 styled-components로 만든 컴포넌트들을 하나의 파일에 같이 작성을 해주게 되면 가독성에 좋지 않기 때문에 하나의 컴포넌트 폴더 내부에 index.jsstyles.js로 분리해서 styles.js 파일 내에는 styled-components로 작성해준 컴포넌트들만 따로 분리해서 작성해주도록 한다.

ex)
/components/ImagesZoom/index.js
/components/ImagesZoom/styles.js

해쉬 태그를 위한 정규 표현식

참고 사이트 : https://regexr.com/

(1) //g : g는 여러개 요소를 찾는 옵션
(2) /#./g : .은 # 뒤에 한 개 문자까지 선택
(3) /#../g : ..은 # 뒤에 두 개 문자까지 선택
(4) /#.+/g : .+는 # 뒤의 모든 문자들을 선택
(5) /#[^\s#]+/g : 공백(\s)을 제거하고 다음 해쉬 태그 기준으로 끊기

split 메서드와 함께 사용하는 경우에는 아래와 같이 정규표현의 조건부를 괄호로 감싸줘야 한다.

1
2
3
/(#[^\s#]+)/g;

'첫 번째 게시글 #해시태그 #익스프레스'.split(/(#[^\s#]+)/g);

210514 Redux vs Mobx vs ContextAPI

React
Redux Mobx ContextAPI
원리가 간단하다. 어플리케이션이 별로 크지 않은 경우에 사용하도록 한다.
에러에 대한 추적이 가능하다. 에러에 대한 추적이 불가능하다.
코드의 양이 많다. 코드의 양이 적다.(생산성이 높다)

비동기 요청을 했을때에는 요청에 대한 실패에 대비를 해야 되기 때문에 이런 처리부분에 대해 해당 상태관리 라이브러리가 제공하는지에 대해 고려해서 사용해야 한다.(대기, 성공, 실패) 이 부분에 대해 Redux와 Mobx는 제공이 되지만, ContextAPI의 경우에는 직접구현을 해야한다.

210514 React TIL - ContextAPI의 사용, Custom Hook(useContext + React.createContext), Strict mode, action 객체와 reducer 함수의 작성, React에서 상태관리의 위치

20210418 Update - Custom hooks - context.js
20210514 Update - Custom hooks(input)

React

본 포스팅 내용은 과거에 개인적으로 공부할때 정리했던 ReactJS의 내용을 복습의 목적으로 다시 정리하는 포스팅입니다.

실습 Repository : https://github.com/LeeHyungi0622/react-basic-projects/blob/master/sidebar-modal/src/context.js

ContextAPI의 사용 & Custom Hook(useContext + React.createContext)

여지까지 ContextAPI를 모든 하위 컴포넌트들의 상위 컴포넌트에서 정의해서 사용했었는데, 이 ContextAPI부분을 별도의 파일로 정의를 해서 사용할 수 있다.
이렇게 별도의 context.js파일로 작성해서 관리를 하면 코드를 좀 더 가독성 좋게 만들 수 있는 것 같다.

그리고 ContextAPI에서 전달하는 값을 사용하는 하위 컴포넌트들에서는 매번 useContext를 import해서 인자로 React.createContext() 객체를 인자로 넣어서 값을 호출해서 사용하였는데 이 부분은 별도의 custom Hook으로 정의해서 사용을 할 수도 있다.

(custom Hook을 만들어서 사용할때에는 함수의 이름에 접두사 use를 꼭 붙여줘야 한다.)

context.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import React, { useState, useContext } from 'react';

const AppContext = React.createContext();

const AppProvider = ({ children }) => {
// modal, sidebar state
const [isSidebarOpen, setIsSidebarOpen] = useState(false);
const [isModalOpen, setIsModalOpen] = useState(false);

const openSidebar = () => {
setIsSidebarOpen(true);
};

const closeSidebar = () => {
setIsSidebarOpen(false);
};

const openModal = () => {
setIsModalOpen(true);
};

const closeModal = () => {
setIsModalOpen(false);
};

return (
<AppContext.Provider
value={{
isModalOpen,
isSidebarOpen,
openModal,
openSidebar,
closeModal,
closeSidebar
}}
>
{children}
</AppContext.Provider>
);
};

// Custom Hook(useContext + AppContext)
export const useGlobalContext = () => {
return useContext(AppContext);
};

// index.js에서 최상위 App.js를 감싸주기 위해 AppProvider를 export해준다. (index.js)
export { AppProvider };
Read more

210501 Setting up my own webpack with react and babel

REACT, WEBPACK, BABEL

CRA을 사용하지 말고, 나만의 React 프로젝트를 위한 웹팩을 만들자

React프로젝트를 만들때 CRA를 사용해서 손쉽게 React 프로젝트를 생성 할 수 있다. 하지만 이렇게 프로젝트를 생성하다보면, 막상 Webpack을 직접 커스텀해서 해야할때 마냥 어렵게만 느껴지고, 프로젝트에 불필요한 요소들이 자동으로 생성되기 때문에 좋지 않다.

기본적으로 설치해야 될 패키지들은 아래를 참고하자.
package.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
"dependencies": {
"react": "^17.0.1",
"react-dom": "^17.0.1",
},
"devDependencies": {
"@babel/core": "^7.11.6",
"@babel/preset-env": "^7.11.5",
"@babel/preset-react": "^7.10.4",
"@pmmmwh/react-refresh-webpack-plugin": "^0.4.3",
"babel-loader": "^8.1.0",
"react-refresh": "^0.9.0",
"webpack": "^5.3.2",
"webpack-cli": "^4.1.0",
"webpack-dev-server": "^3.11.0"
}
Read more

210501 babel / webpack / react-scripts

 React/Babel/Webpack

본 포스팅 내용은 과거에 개인적으로 공부할때 정리했던 ReactJS의 내용을 복습의 목적으로 다시 정리하는 포스팅입니다.

react-scripts

react-based project를 사용할때 직접 빌드 환경을 셋팅하는 것은 많은 시간이 소요된다. 그래서 React 개발팀이 react-scripts라는 npm 패키지를 만들었는데, 이 패키지에는 평균적인 React app에서 많은 사람들이 필요로하는 것들에 대한 기본적인 setup을 포함하고 있다.
위에서 설명한 Babel과 Webpack 또한 react-scripts의 dependency로써 포함되어있다.

babel

babel은 높은 버전의 ECMAScript(unsupported or cutting-edge)를 ES5로 변환해주는 역할을 하는 transpiler이다. (ES5는 범용적인 브라우저에서 지원을 하기 때문)

webpack

webpack은 dependency를 분석기이자 module bundler이다. 예를들어 module A가 B를 dependency로 요청을하고, module B가 C를 dependency로 요청을 한다면 webpack은 C-B-A 와 같이 dependency map을 생성한다. 실제로는 매우 복잡하지만, 기본적인 컨셉은 webpack이 모듈들을 복잡한 dependency 관계들과 함께 번들들로 통합한다.

webpack과 babel의 관계: 웹팩이 종속성을 처리할 때, 웹팩은 자바스크립트 위에서 작동하기 때문에 모든 것을 자바스크립트로 변환해야 한다. 그 결과, 다른 로더를 사용하여 다른 유형의 리소스/코드를 javascript로 변환한다. ES6 또는 ES7에 대한 변환이 필요할 때에는 babel-loader를 사용해서 webpack과 babel을 연결시켜 사용한다.

210430 React Redux

2021/05/13 Update - createSelector shopping cart 연습예제

React Redux

React는 프레임워크가 아닌 라이브러리?

상태관리 라이브러리에 대해서 포스팅을 하는 글에서 갑자기 뜬금없이 React가 프레임워크인지 아닌지에 대한 이야기를 하는 이유는 React에서는 상태관리와 라우팅을 기본적으로 제공하지 않기 때문에 라이브러리로 분류한다는 이야기를 하기 위해서이다. Vue와 Angular에서는 자체적으로 상태관리를 지원하기 때문에 프레임워크라고 하지만 React는 다르다.
하지만 생태계 자체로써 봤을때에는 React도 프레임워크이다.

React의 상태관리 라이브러리의 선택지 Redux와 MobX

React는 Vue와 Angular와 다르게 자체적으로 상태관리를 지원하지 않기 때문에 Redux나 MobX를 선택적으로 사용해서 상태를 관리한다.

ContextAPI + useReducer가 Redux와 MobX를 대체할 수 있다?

JavaScript를 ContextAPI+useReducer라고 하고, jQuery를 Redux나 MobX라고 비유한다면, ContextAPI+useReducer의 조합으로 Redux나 MobX를 구현할 수 있다는 결론이 나온다. 하지만 손쉽게 사용할 수 있도록 이미 만들어져 있는 Redux나 MobX를 사용하는 것이 좋다.

Read more