frontend 개발중

front-end+maketing

0%

간략개요

리액트를 이용한 뉴욕타임즈 기사 검색 프로젝트입니다. 자신이 보고자 하는 뉴욕타임즈기사를 검색하는 것을 목적으로 하고 있습니다.

📚 메인 기술

이틀동안의 진척 상황

전체적으로 팀원분들께서 잘 해주고 계신다.
검색 input 기능과 딜레이 기능 그리고 뷰관련 기능을 각각 담당하게 되었고 서로 의견교환과 git을 통한 관리도 서로 배우면서 공부가 되고 있다.

기타 요구사항

  • create-react-app 사용
  • react-router-dom 사용
  • redux 사용
  • 스타일링 및 방식은 자유 (css, styled-components 등)
  • nyt api token은 본인이 가입하여 발급하기

겨우겨우 풀었다. 몇가지 테스트를 통해서 문제가 정답이 나오는 것을 확인 검수도 받았다.

문제 회장선거

현수네 반은 오늘 회장선거를 합니다. 현수네 반 N명의 학생은 각자 자기가 좋아하는 학생을
회장후보로 추천합니다. 한 학생이 여러명을 추천할 수 있습니다.
추천횟수가 k번 이상인 학생들만 회장선거에 출마할 수 있습니다. 회장선거에 출마한 학생들
은 자기를 추천해준 학생들에게 감사의 이메일을 보내기로 했습니다.
매개변수 votes에 추천정보가 주어지면 0번 학생부터 N-1번 학생까지 각 학생이 감사이메일
을 받는 횟수를 알아내는 프로그램을 작성하세요

정답

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
function solution(n,votes, k) {
let result=Array(n).fill(0)
let elected=[]
let sH=new Map()

for(let x of votes){
sH.set(x[1],(sH.get(x[1])||0)+1);
}

let resultArr=Array.from(sH)
resultArr.map((e,i)=>{
if(i<n){
if(e[1]>=k){
elected.push(e[0])
}
}
})
votes.map(e=>{
elected.map(item=>{
if(item===e[1]){
for(let i=0;i<n;i++){
if(e[0]===i){
result[i]+=1
}
}
}

})
})

return result


}

살짝 순서대로 설명을 하자면 먼저

  1. 맵핑을 한뒤 회장 선거에 나오는 사람을 검색한다. sH.set(x[1],(sH.get(x[1])||0)+1);
  2. 결과를 맵으로 변경한뒤에 투표수가 k이상 인 사람을 체크
    if(e[1]>=k){ elected.push(e[0]) }
  3. 전체 결과를 map으로 돌린뒤에 투표한 사람과 당선된 사람을 비교하여 초기에 만들어둔
    배열에 존재할 때마다 하나씩 추가해준다. if(e[0]===i){ result[i]+=1 }

한시간 이상은 걸린 것 같다. 일단 문제 푸는 것에 주력하고 나중에는 시간도 단축할 수 있도록 노력해보자

주말동안 밤새면서 만들던 작업 정리

  1. mysql 과 phpmyadmin 설치를 통해 나만의 DB 만들기

ec2에 이것저것 설치하면서 과거 배웠던 php나 db커넥트 방식을 다시 써보게 되서 감회가 새롭다.
자세한 설치 방식은 apt-get 형식으로 php-fpm 을 설치하였고 php-cil 그리고 phpmyadmin 설치

1
2
3
$ sudo apt update
$ sudo apt install phpmyadmin

  1. phpmyadmin
    DB작성은 예전 많이 해서 문제는 없었는데 mysql 업데이트로 파티션 나누는 방식이 생겨 언제 한번 공부를 생각중이다. 지금은 할게 많아서…

upload successful
primary key 설정과 auto increment 설정은 따로 지정하였다. 한국어로 쓸 예정이라 데이터 정렬은
utf8mb3 일반으로 설정하였다.

  1. php 형식으로 GET,POST 받아보기 테스트
    nginx를 사용하여 예전 사용했던 아파치 서버의 .htaccess 를 사용하지 못해 아직도 GET 방식만 성공할수 있었다. 다른 방식이 있나 언제 시간나면 다른 분들께 물어볼 예정

GET 방식은 아래와 같은 방식으로 받아보았다.

upload successful

1
2
3
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: *");
header("Access-Control-Allow-Methods: *");

Access-Control-Allow-Origin을 통해 CORS 문제를 방지하였고 sql문을 통해서 전체적인 내용이 나오도록 처리하였다. 혹시 id를 개별로 GET방식으로 쿼리를 날렸을때는 따로 볼수있도록 처리해보았다.
laravel 이 되었다면 이런 하나하나 짤 필요도 없을것은 엄청 고생해서 설정하게 되었다.

  1. remote ssh 사용을 통해 좀더 원할하게 서버 접근가능하게 하기

upload successful

vscode 확장기능을 통해서 설치하였고 설정방식은 윈도우라면 ctrl+shift+p를 하고 remote ssh의 내용을 체크한뒤 비밀키 장소를 설정하고 도메인주소를 입력하면 성공적으로 동작할 것이다.

  1. 생각보다 너무 오래 걸려서 좀 더 쉽게 api 서버를 만들 방법을 찾는중

생각보다 aws 람다식과 게이트웨이 방식으로 쉽게 만들수 있다는 이야기가 있어서 현재 공부중인데 이것보다 엄청 간단한것같다. 다 만들어진다면 한번 블로그에 정리할 예정이다.

그 외 여러가지 문제 생긴 것 공유

  1. npm은 여전히 동작하지 않는다.
    아직도 이유를 모르겠다
  2. curl 도 동작하지 않는다
    이것도 이유를 모르겠다. apt-get이 된다는건 보안상 문제는 아닌 것으로 생각되는데..

현재 만난 에러가 제법 되지만 가장 짜증나는 부분만 몇개 기록해보려고 한다.

ec2 서버 개설은 완료

예전에 한번 만들어본 경험이 있어 다른 메일로 개설은 완료 그렇지만 다른 부분에서 여러가지 문제가 생겼다.

npm 설치에서부터 고난

aws 사이트에서 설치가이드를 제공했지만

[공식사이트] https://docs.aws.amazon.com/ko_kr/sdk-for-javascript/v2/developer-guide/setting-up-node-on-ec2-instance.html

1
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash

upload successful
위의 curl 커멘드가 먹히지 않는다.. total 시간만 계속 지나가고 설치가 되지않아서 우분트의 apt 을 통해서 nodejs를 설치하였다.

1
2
$ sudo apt install nodejs
$ sudo apt install npm

겨우겨우 설치까는 완료했지만 문제는 아직 npm 이 잘 먹히지 않는다..

upload successful

위의 사진처럼 buildDeps 를 끝으로 설치가 안된다. npm init -y 는 문제없는데 무슨 이유일까 여러곳을 찾아봤지만 해결이 어려워 일단 한번 다 삭제를 실행해보았다

이번엔 또다른 에러

upload successful
Cannot read property ‘insert’ of undefined 이건 또 왜 안되는지 모르겠다. 결국 1번 문제의 Currnent speed 가 0이 나온 에러를 중심으로 다시한번 도전…
결국 해결하지 못해서 api 작성은 나중으로 조금 미루기로 했다.

일단 같은 문제에 대해서 스텍오버플로우에 질문이 있어서 답이 있나 찾아봤지만 아직 답변이 없어서 기다려서 문제를 한번 풀어보려고 한다.

https://stackoverflow.com/questions/72004247/npm-install-error-npm-err-cannot-read-property-insert-of-undefined

개발 단계의 순서

어떤 프로그램을 만들것인가?

먼저 요구사항을 분석하고 설계 구현 테스트 라는 단계를 걸처셔 완성적인 사이트 혹은 앱이 개발된다. 그렇다면 요구사항의 분석이 일단 완벽하게 되었다고 가정해보자.

설계라는 것은 어떤 것을 설계해야 할 것인가

지금까지 경험해온 부분과 그리고 현재 정리를 해보려고 한다.

  1. 어떻게 테스트를 할 것인가?
    유닛 테스트 그리고 단위 테스트와 Cypress 와 같은 tool로 테스트하는 것은 누구나 생각할 수 있지만 react 와 같은 경우 컴포넌트 단위에서 초기부터 어떤 테스트를 통과해야 할지는 정하는 것이 필요할 것으로 생각한다.
    예를 들면 input html 이 존재한다면 모든 input은 여러가지 값을 넣어서 submit해도 아무런 error가 나지 않게 설계할 것을 처음부터 명시한다면 좋을 것으로 생각한다. 물론 테스트 중요사항은 요구사항에 따라 매우 크게 달라질수도 있다. 아래부분도 마찬가지이다.

  2. 어떻게 그리고 어디에 배포를 할것인가?
    aws를 통해서 배포를 할 것인지 혹은 작은 단위에서 배포를 통하여 vercel과 같은 사이트를 통해서 배포를 한다고 할때도 기본적인 준비사항이 필요하다. 그것을 공부할 필요도 있다.

  3. tool은 어떤 것을 사용할 것인가
    create-react-app 을 그대로 사용할 것인지 혹은 처음부터 하나하나 webpack 설정까지 하나로 할 것인지도 설계 단계에서 생각해낼 부분이다.

  4. api와 데이터 파싱의 방식을 정하는 것

db를 사용한다면 어떤 db를 사용할것인지 그리고 api 라면 그 api의 구조를 개발인원끼리 파악하는 것이 중요하다. 이미지 처리는 어떻게 할 것이며, 영상이 있다면 또 어떻게 처리할지도 고민해볼 사항이라고 생각한다.

  1. 요구사항이 중간에 변경되었을때를 대비하는 것

실제 자주 있는 일이기에 요구사항이 변경될 수도 있다는 것을 대비하며 설계를 준비하는 것도 필요할 것으로 생각한다.

그 외에도 여러가지 존재하겠지만 지금 생각나는 부분은 이정도이다.

reduce

아직 익숙치 않은 javascript 방식중에서 reduce는 아직 제대로 써보지않아서 연습중이다.
연습한 내용을 한번 적어보면서 복습을 해보자

1
2
3
4
5
6
7
8
9
10
function solution(arr){
var sum = arr.reduce(function (prev, cur) {
return prev + cur;
},0);

return sum
}
solution([5, 3, 7, 2, 3])
// 최종 합 20 출력

prev는 누산기로서의 역할을 하며 그전값을 대신해주기도 한다. cur은 현재 값이라서
실행 순서는 prev=0 + cur= 5 => prev=5 +cur =3 => prev=8+cur=7 => prev=15+cur=2=> prev=17+cur=3
라는 실행을 한번에 실행하여 결과값을 제시해주는 것이 reduce이다.

1
2
3
4
5
let arr = ["경기도", "수원시", "팔달구"];
let result = arr.reduceRight((acc, element) => acc + " " + element);

/// reduceRight는 배열이나 object 의 오른쪽으로부터 시행되는 함수이다.

이와 같이 reduceRight라는 함수도 존재한다.

구체적인 예시는 아래 링크로 공부하고 있다.

[JS-📚-배열-고차함수-reduce]
https://inpa.tistory.com/entry/JS-%F0%9F%93%9A-%EB%B0%B0%EC%97%B4-%EA%B3%A0%EC%B0%A8%ED%95%A8%EC%88%98-reduce

먼저 thunk란, 특정 작업을 나중에 하도록 미루기 위해서 함수형태로 감싼것을 칭합니다.
그것이 바로 미들웨어를 통하기때문이 아닐까 생각해본다

왜 redux-thunk 를 쓸까

redux의 기본 골격은 보면 순수함수로 이루어진 action.type으로 스위치문으로 판별뒤 값을 리턴하는 방식으로 진행됩니다. 그렇기에 어떤 액션을 통해 dispatch 함수를 실행시킬 경우 결과는 항상 return 값으로만 남기 때문에 비동기를 실행을 시켜버리는 것과 값을 가져오는 것은 큰 차이가 있기에 기본적으로 불가능하다.
그렇기에 아래와 같은 미들웨어를 만들어주고 그 뒤에 typeof action=== ‘function’ 이라는 구문을 추가해 함수를 파악하고 그 자체를 실행시켜주는 방식으로 하는 것이 필요해져서
store.dispatch를 이용하는 것이라고 할 수 있다.

1
2
3
const createThunkMiddleware=extraArgument=>next=>action =>{
...
}

아래의 함수는 결국 위의 함수 방식과 다르지 않기에 실행 순서도 좀 더 명확하게 파악이 가능하다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function createThunkMiddleware(extraArgument) {
return ({ dispatch, getState }) => next => action => {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
// 이부분이 thunk의 핵심

return next(action);
};
}

const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;

export default thunk;

npm i redux-thunk

1
const store = createStore(modules, applyMiddleware(logger, ReduxThunk))

위의 작은 방식으로도 현재는 아주 깔끔하게 provider에 store를 이용하고 비동기 처리도 dispatch 가능하다. 물론 react-redux 의 connect와 같이 쓰는 방식이 가장 유용하다고 생각한다.

next.config.js 설정에 대해서

img 파일을 불러올때 next config 에서 설정을 해주지 않으면 Invalid src prop 라는 에러가 생긴다. 이부분에서 좀 더 설정에 대해서 공부를 해보자 라는 생각이 들었다.
이부분을 해결하는 방식은 간단한데 유효하지 않은 src 라는 것이니 유효한 src라고 config 파일에서 선언해주면 된다는 것이다.

1
2
3
4
5
6
7
8
9
10
11
12
const nextConfig = {
reactStrictMode: true,
swcMinify: true,
images: {
domains: [
'해당 도메인'
],
format: ['image/png', 'image/webp', 'image/jpeg', 'image/gif']
}
}

module.exports = nextConfig

reactStrictMode 라는 것은 애플리케이션의 잠재적인 문제를 강조하기 위한 개발 모드 전용 기능이다. 수명 주기, 레거시 API 사용 및 기타 여러 기능을 식별하는 데 사용된다. 왠만하면 개발 공부중에는 써볼 예정이고 안쓸때와 쓸때의 다른 점을 좀 더 공부해보려고 한다.

swcMinify라는 부분도 조금 공부해봤는데 바벨과 비교해서 생각해보니 나중에 좀 더 깊게 공부할 내용이라 생각되었다. 일단 써보기로… 바벨보다 빠르다고 한다!

추가 부분에 대해선 이쪽에서 좀 더 알려주어서 한번 읽어보았다!
https://im-developer.tistory.com/230

images부분이 현재 필요한 부분이라 api 에서 불러주는 url 을 넣어서 해결하였다!

redux middleware의 템플릿

리덕스 미들웨어를 만들 땐 다음 템플릿을 사용하는 것을 원칙으로 한다고 한다

1
2
3
const middleware = store => next => action => {
// 하고 싶은 작업...
}

위와 같은 방식을 커링 기법이라는 것을 이번에 배웠다.
[커링 기법]:https://ko.javascript.info/currying-partials

그냥 코드적으로 생각하면 밑의 내용과 같다

1
2
3
4
5
6
7
function middleware(store) {
return function (next) {
return function (action) {
// 하고 싶은 작업...
};
};
};

결국 고차함수 방식으로 매개변수를 store 로 주고 리턴값을 함수로 주어서 그 함수가 다시 action을 매개변수로 받는 형식으로 진행된다.

첫번째 store는 redux에서 항상 사용하는 데이터 저장장치이다. 이 안에 dispatch, getState, subscribe 내장함수들을 통해서 실행 구독 스테이트의 상태를 가져오는 것이 가능하다. 그렇다면 이 방식은 왜 사용하는가?

middleware를 사용하는 이유

간단히 생각하면 redux의 문제가 있기 때문이다. 다시 한번 redux 로 돌아가서 생각해보자

1
2
3
4
5
6
7
8
9
10
11
12
13
function reducer(state = InitializeState , action) {
// do something
switch(action.type) {
case ActionType.INCREASE:
return { ...state, count: state.count + 1 };
case ActionType.DECREASE:
return { ...state, count: state.count - 1 };
case ActionType.RESET:
return { ...state, count: 0 };
default:
return { ...state };
}
}

일반적인 reducer 함수이다. 이와 같은 함수를 redux에서는 매개변수로 받기에 값을 받지 않으면 undefined 가 나와 버린다. 예를 들어 ActionType.INCREASE: return { …state, count: state.count + 1 }; 이 아니고 setTimeout과 같은 함수를 리턴 해버리면 결국 값은 나오지 않는다. 순수함수이기 때문이다. 그렇기에 middleware를 reducer와 같이 받아서
createStore 와 같은 기초적인 redux 함수로 처리하는 것이 필요하다.

redux의 중요성을 배웠다

결국 웹사이트 혹은 웹에서의 상태는 매우 중요하다. 현재 사용자가 어떤 component를 다루는 것에 따라 최상단의 상태정보가 필요할 수도 있고 반대도 가능하다. 하지만 그렇다고 해서 props로 모든 정보를 끌어오는 것은 유지 보수 관점에서 따지면 최악일수 밖에 없다. 예를 들어 form component 에서 받은 정보를 최상단 app컴포넌트에서 가장 밑 딴인 data component에서 추가적으로 상태를 추가했을때 어디서부터 어디까지 수정이 필요할지 파악하기가 매우 힘들것을 예상할 수 있다.

그렇기에 최상단에서 필요한 정보만을 가져오고 또한 변경할 수 있는 수단이 현재 react에서 많이 사용하는 redux이다
강의에서 배운건 자바스크립트로도 쉽게 표현 가능하다. 김민태 강사님이 말해주는 방식이 매우 정리가 잘되서 여기도 올려서 한번 정리해보고자 한다.

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
function createStore() {
let state;
let handlers = [];

function send(action) {
state = worker(state, action);
handlers.forEach(handler => handler());
}

function subscribe(handler) {
handlers.push(handler);
}

function getState() {
return state;
}

return {
send,
getState,
subscribe,
};
}

function worker(state = { count: 0 }, action) {
// do something
switch(action.type) {
case 'increase':
return { ...state, count: state.count + 1 };
default:
return { ...state };
}
}

const store = createStore(worker);

store.subscribe(function() {
console.log(store.getState());
});

store.send({ type: 'increase' });
store.send({ type: 'increase' });

  1. 먼저 상태를 저장시켜야하기 때문에 함수 createStore를 작성해준다.
  2. 함수 createStore를 통해 상태를 전달해야하기에 현재의 상태와 그 상태를 만들어주는 핸들러(함수)를 먼저 작성해본다
  3. 함수를 저장하기 위해서는 함수를 구독하는 방식 [] 에 push를 해서 따로 받아 줄 수 있도록 정리해본다
  4. state를 어떤 방식으로 보낼 것인지는 프로그래머가 지정하기에 worker라는 함수로 임시지정하여 action.type에 따라서 상태값이 달라지게 설정한다.
  5. store를 만들었고 그 만든 store에 함수를 지정하였고 그 뒤 실행하면 상태의 변화없이 어느 곳에서든 사용가능한 방식이 가능해진다.

이런 방식의 강의를 듣고 머리 속에 그림이 조금 그려지게 되었다. redux에 대해 미들웨어 같은 부분도 정리해볼 생각이다.