Redux-saga Angular / React

Redux Saga는 기존 redux에서 서버와의 비동기 통신을 담당하는 라이브러리 이다. 보통 이건 순수함수를 벗어나게 되는 데이터 송수신 등 좀 더 순수함수 스럽게(?) 보이도록 바꿔주는 역할이다.

만약 Redux Saga를 쓰지 않으면, 외부 API에서 값을 받아오는 코드는 어떻게 자이게 될까? 프로미스 콜백 지옥이 될 것이다. 게다가 한 dispatch가 한 action만 바라보는 집중도가 떨어지게 된다. action에다가 콜백 혹은 프로미스로 본인의 작업 완료시 또 뭘 해야할지를 가지고 있어야 하니까.

Redux Saga같은 경우는 별개의 공간에서 dispatch 및 store를 관찰(?)한다. 그리고 그에 따른 행위를 별개로 지정할 수 있기 때문에 dispatch 및 action 등이 더러워질 일이 없다. 이 때 Saga가 가지는 개별적인 행위는 task라고 한다.

예시는 다음과 같다.

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const memoAction = function*() {
yield put({ type: TYPES.LOADSTART, payload: "off" });
const movie = yield getMovieData();
yield put({ type: TYPES.ADDMOVIE, payload: movie });
yield delay(1000);
yield put({ type: TYPES.LOADEND, payload: "on" });
};
export const rootSaga = function*() {
/*
saga 에는 여러가지 메서드들이 있다. (import 해서 쓸 수 있다)
take, takeLatest -> 특정 액션 감시후 비동기 로직 동작하도록 할 수 있음.
put -> dispath 여기서 바로 액션 실행?
delay -> 실행 지연.
fort -> 새로운 하위 태스크 생성, 즉 연속해서 담에 뭐할지를 붙여주는것. (블럭X)
call -> 새로운 하위 태스크 생성, 즉 연속해서 담에 뭐할지를 붙여주는것. (블럭o)
state -> 스토어에서 가져올때 사용. (블럭o)
*/
// 실행을 리스너가 받기까지 멈춰놓고 next를 호출하는 방식이라 저렇게 제너레이트를 걸어놓아야 하는 듯 함
yield takeLatest(TYPES.ADDCLICK, memoAction);
};


이걸 바로 쓸 수 없고 redux store 에다가 middleware로 등록해줘야하 한다.

1
2
3
4
5
6
7
8
import createSagaMiddleware from "redux-saga";

// 미들웨어 -> 양쪽에서 데이터를 주고 받을 때 중간에서 매개역할 해주며 원래 없는 기능을 불어넣는것.
export const sagaMiddleware = createSagaMiddleware();
export const rootStore = createStore(
rootReducer,
applyMiddleware(sagaMiddleware) // 스토어에 미들웨어 등록
);


자세한 예제는 다음 주소에서 확인할 수 있다. 





Redux Angular / React

Redux는 flux 패턴에 영감을 받아 만들어진 react의 중앙 state 관리 라이브러리 이다. 이것을 이용하면 컴포넌트끼리 굳이 여러번 거치지 않고 동일 state를 참조할 수 있다.

서로 직계 부모가 다른 컴포넌트끼리 값을 주고 받으려면 어떻게 해야 하는가? (Vue에서는 이벤트 버스 등을 사용하는데, 이건 논외로 하고) Redux가 없이 쓰려면 동일한 부모가 나올 때까지 함수를 올렸다가. 서로 원하는 컴포넌트까지 순차적으로 정리 해주서야 한다. 이 불편함을 해소하는데 쓰는 것이 redux 이다.

Redux의 전체적인 흐름을 보기 전에 사전에 알고 있어야 할 것들을 간략하게 정리하도록 하자. http://saysun12.egloos.com/1948273 참고

1. Action
  =>어떤 행위를 하고, 그 행위가 어떤 데이터를 동반하는지 (payload)를 지정해 놓은 것.

2. Dispatch
  =>Store 란 주체에다가 Action을 전달해 주는것. 

3. Store (Reducer+)
  => 데이터 보관소 (state) 및 그 데이터에 대한 로직이 담긴 인스턴스 , Redux 에서는 Reduce, Middlewarer의 묶음으로 사용한다.

4. View
  => Store를 구독하여 그 state를 화면에 표출 및 Event를 통해 Dispatch 호출.


이것들을 묶어서 아래와 같은 그림으로 표현할 수 도 있다.


위 그림은 리덕스에서의 기본 데이터 흐름을 그림으로 표현한 것이다. 여기서는 (1) Action, (2) Dispatch, (3) Store, (4) Reducer 로 나뉠  수 있다.


1. Action
(4) 리듀서에게 전달할 자신의 행동패턴과, 그에 따라 뭘 전달할지를 지정한다. 위 그림에서는 전달할 데이터가 고정되어 있는데 이래서는 쓸모가 없다. 그래서 생긴 패턴이 액션 생성자 패턴이다. 자세한 소스와 부연설명 이미지는 아래와 같다.

 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
export const TYPES = {
CHANGE: "CHANGE",
ADDCLICK: "ADDCLICK",
ADDMOVIE: "ADDMOVIE",
LOADSTART: "LOADSTART",
LOADEND: "LOADEND"
};

// 액션 생성자 이 녀석을 dispath함
export const ACTION_CREATOR = {
changeStar: f => {
return { type: TYPES.CHANGE, f: f }; // 두번째 매개변수는 내가 바꿀 새로은 데이터를 리턴하는 함수
}
};

export const ADDCLICK = {
addMovie: f => {
return { type: TYPES.ADDCLICK }; // 두번째 매개변수는 내가 바꿀 새로은 데이터를 리턴하는 함수
}
};


2. Dispatch
매개변수를 이용해 (4) 리듀서에게 특정 액션을 전달해준다, 이 때 위에서 말했던 액션 생성자를 사용한다. 실제 사용법은 "react-redux" 에서 제공하는 connect를 이용해 필요한 component를 매핑해 주는 것이다.

1
2
3
4
5
6
const mapDispatchToProps = dispatch => {
return {
changeStar: (f, index, star) => dispatch(ACTION_CREATOR.changeStar(f, index, star)), // 액션 생성자 함수는 여기에 연결.
addMovie: () => dispatch(ADDCLICK.addMovie()) // 액션 생성자 함수는 여기에 연결.
};
};


1
2
3
4
export const MovieComponent = connect(
mapStateToProps, // state를 props로 사용
mapDispatchToProps // dispatch 기능을 props로 사용
)(Movie); // Movie를 connect가 래핑한 다음에 내보내서 사용할수 있도록 해주는것


3. Store
메인 저장소이다. redux 에서는 reduce 및 middlewarer의 조합으로써 이뤄진다. 또한 만들어진 store는 렌더시 등록을 해야지만 View와의 관계가 이뤄진다.

 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
import { REDUCER_MOVIE, REDUCER_LOADING } from "./reducer";
import { createStore, applyMiddleware } from "redux";
import { combineReducers } from "redux";
import createSagaMiddleware from "redux-saga";

// 미들웨어 -> 양쪽에서 데이터를 주고 받을 때 중간에서 매개역할 해주며 원래 없는 기능을 불어넣는것.
export const sagaMiddleware = createSagaMiddleware();

export const initialState = [
{
name: "첫번째 무비",
poster: "movie01.jpg",
star: 0
},
{
name: "두번째 무비",
poster: "movie02.jpg",
star: 0
},
{
name: "세번째 무비",
poster: "movie03.jpg",
star: 0
}
];
let rootReducer = combineReducers({
movie: REDUCER_MOVIE,
loading: REDUCER_LOADING
});
export const rootStore = createStore(
rootReducer,
applyMiddleware(sagaMiddleware) // 스토어에 미들웨어 등록
);


1
2
3
4
5
6
// View 렌더링시 등록
const rendering = function() {
ReactDom.render(<App />, document.getElementById("app"));
};
rendering();
rootStore.subscribe(rendering);


전체 예제를 보려면 하기링크를 참고하면 된다. https://github.com/popsapple/reactExamples



eslint 설정 및 간단 사용법 JAVASCRIPT

eslint는 여러 사람이 한 프로젝트를 진행 할 때 코딩 규칙증 강제할 수 있는 방법 중에 하나이다. 미리 규칙을 정의 해 두고 컴파일 시에 오류 여부를 확인할 수 있다. 그러기 위해 처음엔 npm을 통해 필요한 모듈을 설치해야 한다.


npm install -g eslint eslint-config-airbnb-base


그리고 빌드 환경설정을 해 주는데 package.json에서도 가능하지만 나중엔 결국 분리하게 되기 때문에 별도 json으로 반들어 둔다.

 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
{
"plugins": ["a-plugin"], // 사용한 플러그인
"overrides": [
{
"files": ["*.md"], // 연관 파일
"processor": "a-plugin/markdown" // 프로세서(?)
}
],
"parserOptions": { // 파서가 사용할 자바스크립트 기능
"ecmaVersion": 6, // 스크립트 버전 2015[6] ~ 2020[11]
"sourceType": "module", // 코드가 module로 내보내지는 거라면 "module" 쓰고 아니면 "script"
"ecmaFeatures": { // 사용하려는 추가 기능
"globalReturn": true, // 전역 범위가 모듈인지 아닌지
"impliedStrict": true, // global strict 사용.
"jsx": true
}
},
"extends": "airbnb-base", // 다른사람이 써놓은 룰을 가져오는것 거의 에어비앤비꺼면 됨
"parser": "esprima", // 파서 지정
"rules": { // 규칙 - https://eslint.org/docs/rules/ 참고
"semi": ["error", "always"], // 첫번째 매개변수는 에러로표시할 것인가 무시할 것인가 경고로 표시할 것인가. off[0],error[1],wran[2]
"quotes": ["error", "double"]
},
"env": { // 각종 환경변수
"browser" : "", // 전역변수
"mocha": "", // 모카 테스트 전역 변수를 모두 추가합니다.
"jasmine": "", // 모든 Jasmine 테스트 전역 변수를 추가합니다.
"jest" : "", // Jest 전역 변수.
"jquery" : "", // jquery 전역 변수.
"mongo" : "", // mongoDB 전역 변수.
},
"globals": { // 전역 변수 및, 그리고 에러검출에서 제외됨.
"jQuery": "true"
}
}


빌드 실행시에는 하기와 같이 커맨드라인에서 실행해 주면 된다.
eslint "lib/**" -c myconfig.json


실제 프로젝트 진행 시에는 몇몇 파일은 eslint를 무시하고 싶은 것들이 있는데, .gitignore와 마찬가지로 .eslintignore 를 만들어 주면 된다.


1
2
3
/build/**
/cover/**
/doc/**


package.json 표기법 JAVASCRIPT

 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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
{
"name": "reactexample", // 패키지의 나타내는 이름 중복시 npm에 등록할 수 없다.
"version": "1.0.0", // 패키지의 버전을 나타내는 이름 업데이트시 반드시 숫자가 올라가야 한다.
"description": "", // 설명 검색된 리스트에 이게 나타난다.
"keyword": ["react", "study"], // 연관어를 배열로 나타낸다
"homepage": "http://popsapple.herokuapp.com/", // 프로젝트 홈페이지
"bugs": {
// 버그리포트 할 곳들
"url": "",
"email": ""
},
"author": {
// 제작자 정보
"name": "Hyeon",
"email": "saysun34@gmail.com",
"url": "http://popsapple.herokuapp.com/"
},
"contributors": [
// 제작자'들' 정보
{
"name": "Hyeon",
"email": "saysun34@gmail.com",
"url": "http://popsapple.herokuapp.com/"
},
{
"name": "Kim",
"email": "saysun34@gmail.com",
"url": "http://popsapple.herokuapp.com/"
}
],
"files": [], // 프로젝트에 포함된 파일의 배열
"main": "index.js", // 시작되는 포인트, 엔트리포인드 import 혹은 require 하면 바로 들어오는 부분
"scripts": {
// npm run build 이런식으로 cmd 등에 명령어 등록
"build": "webpack --config webpack.config.js"
},
"os": ["win64"], // 동작 운영체제
"engines": { "node": ">=0.10.3" }, // 부등호로 버전 지정 가능
"repository": {
"type": "git",
"url": ""
}, // 소스코드 저장소 위치
"config": {
"port": "7859" // npm 내에서 쓸 수 있는 환경변수 라는데 cross-env 쓰고 말겠다....
},
"dependencies": {
// 사용자에게도 같이 딸려나가는 필요한(의존성을 가진) 패키지 - 빌드 후(?)
},
"devDependencies": {
// 개발자만 필요한(의존성을 가진) 패키지 - 빌드 전(?)
"@babel/core": "~7.8.3", // ~ '>> 지정 버턴의 끝자리만 업데이트 즉 7.8.n 까지만 자동 으로 업데이트 해준다는 것 (하단 이미지의 pathch)
"@babel/preset-env": "^7.8.3", // ^ '>> 맨 앞자리의 까지의 업데이트는 허용하지 않는다. (큰 변화가 없는 정도) 7.n.n 까지 자동 업데이트 (하단 이미지의 major)
"@babel/preset-react": ">7.8.3",// > '>> 보다 높은 버전
"axios": ">=0.19.1",// >= '>> 같거나 낮은 버전
"babel-loader": "<8.0.6", // 보다 낮은 버전
"express": "4.17.1"// 표기한 그대로의 버전
},
"peerDependencies": {
// 이 패키지와 궁합이 맞을 다른
},
"license": "ISC" // 권한...이 아니라 그냥 라이센스
}





구글 크롬 보안설정 끄기 프로그래밍 상식

가끔 웹개발 하다보면 보안때문에 막히는게 있는데, 일반 웹 상에서는 안될 일이지만 웹앱으로 개발할 경우 참고할 수 있도록 적어둔다.

커맨드라인 에서 실행

"크롬실행파일경로" --disable-web-security --user-data-dir="C:\chrome"

1 2 3 4 5 6 7 8 9 10 다음