TIL

오늘 한 일

Javascript30 14차

  • JavaScript References VS Copying

원시 타입과 찹조타입의 복사에 관한 차이와 얕은복사, 깊은 복사에 대한 내용이었다.

다음은 배열을 복사하는 방법이다.(단, 얕은 복사)

1
2
3
4
5
6
const cats = ['Syami', 'Jojo', 'Loki', 'Kkonnim'];

const team1 = cats.slice();
const team2 = [].concat(cats);
const team3 = [...cats]
const team4 = Array.from(cats)

Array.from() 메서드는 배열의 형태를 갖거나 순회 가능한 객체로부터 얕게 복사한 Array 객체를 만듭니다.

다음은 객체를 복사하는 방법이다.(단, 얕은 복사)

1
2
3
4
5
6
const cat = {
name: 'Syami',
age: 10
}

const cat2 = Object.assign({}, cat, { kind: 'korean shot', age: 11})

이러한 복사는 1 레벨의 깊이만 복사가 가능하다. 배열 안 배열 혹은 객체 안 배열 등등의 중첩되어 여러 레벨의 깊이가 생긴 객체(혹은 배열)을 복사하는 방법은 깊은 복사라고 하며 강의에서는 그 방법 중 하나를 소개해 줬는데 다음과 같다.

1
2
3
4
5
6
7
8
9
const cat = {
name: 'Syami',
age: 10,
family: {
brother: ['Jojo', 'Loki'],
sister: ['Kkonnim', 'Samsun']
}
}
const cat2 = JSON.parse(JSON.stringify(cat))

그러나 이 방법은 성능상 매우 안 좋고, 직렬화 할 수 없는 속성들은(prototype이라든가) 날라가 버리기 때문에 좋은 방법은 아니라고 한다.

파이널 프로젝트 2차 준비

서버를 GraphQL로 하자는 얘기가 나와서 다음의 영상들을 보게 되었는데, 많이 도움이 되었다.

그런데 프로젝트에 기획했지만 아직 구현되지 못한 부족한 부분이 많고, 처음부터 Apollo client를 쓰려니 잘 이해되지 않는 부분이 많아서 먼저 리덕스로 변경하는 것부터 처리하는 게 좋을 것 같아 리덕스를 먼저 해보기로 했다.

Share Comments

Judge Route Circle

leetcode 문제링크

Initially, there is a Robot at position (0, 0). Given a sequence of its moves, judge if this robot makes a circle, which means it moves back to the original place.

The move sequence is represented by a string. And each move is represent by a character. The valid robot moves are R (Right), L (Left), U (Up) and D (down). The output should be true or false representing whether the robot makes a circle.

Example 1:

  • Input: “UD”
  • Output: true

Example 2:

  • Input: “LL”
  • Output: false

나의 풀이

문제 자체를 이해하기가 좀 어려웠다. 괜히 Circle이라 그래서 왜 원이 되지?라고 생각했는데, 그림을 그려보면 이해하기 쉬웠다. 예를들면 “RLUURDDLU”를 좌표 (0, 0)에서 시작한다고 생각해서 방향따라 그려보면 결국 다시 (0, 0)의 위치로 오게 된다. 이 경우 로봇이 원을 만든다고 가정하여 true를 반환하면 된다. 그래서 “LDRRLRUULR”의 경우 그려보면 (0, 0)의 위치로 돌아오지 않기 때문에 false를 반환하면 된다.

정규식을 이용했다. R과 L의 수와 U와 D의 수가 같으면 원 위치로 되돌아갔다고 할 수 있으니까 다음과 같이 접근해서 풀어보았다.
|| []이 부분은 마지막에 length로 구하고 싶은데 match 메소드가 정규식에 부합하는 문자열이 있으면 배열 형태로 반환하지만 없을 경우 null로 반환하기 때문에 정규식에 일치하는 문자가 없을 경우는 빈배열이 담기도록 하기 위해 추가했다.

1
2
3
4
5
6
7
8
// 68ms
var judgeCircle = function(moves) {
const R = moves.match(/R/g) || [];
const L = moves.match(/L/g) || [];
const U = moves.match(/U/g) || [];
const D = moves.match(/D/g) || [];
return R.length === L.length && U.length === D.length
};

이번에는 for문을 통해 문자열을 하나씩 탐색해서 x와 y의 값에 변화를 주는 방법을 사용했다. 오른쪽으로 이동하면 x좌표가 1추가되고 왼쪽으로 이동하면 x좌표가 1 감소하는 것이라 모든 문자열을 탐색한 뒤에 x와 y의 좌표가 다시 0이 되었는지 확인한다.

1
2
3
4
5
6
7
8
9
10
11
12
// 72ms
var judgeCircle = function(moves) {
let x = 0;
let y = 0;
for (const i of moves) {
i === 'R' ? x++ :
i === 'L' ? x-- :
i === 'U' ? y-- :
i === 'D' && y++;
}
return x === 0 && y === 0
};

같은 접근법인데 reduce 메소드를 이용해 본 방법

1
2
3
4
5
6
7
// 72ms
var judgeCircle = function(moves) {
const arr = moves.split('');
const hor = arr.reduce((acc, item) => acc + (item === 'R' ? 1 : item === 'L' ? -1 : 0), 0);
const ver = arr.reduce((acc, item) => acc + (item === 'U' ? 1 : item === 'D' ? -1 : 0), 0);
return !(hor + ver)
};

다른 사람 풀이

같은 접근법인데 60ms이길래 환경이 달라서 그런 것 같아서 내가 다시 넣고 돌려보니 72ms가 걸렸다. 각 변수로 x, y를 넣는 대신 배열로 두고 switch 문을 사용한 방법이다.

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
// 72ms
var judgeCircle = function(moves) {
var origin = [0,0]
for(var i = 0; i < moves.length; i++){
switch(moves[i]){
case 'U':
origin[0]++
break
case 'D':
origin[0]--
break
case 'L':
origin[1]--
break
case 'R':
origin[1]++
break
}
}
if(origin[0] == 0 && origin[1] == 0){
return true
}else{
return false
}
};


문제의 좋아요와 싫어요 수가 거의 비슷해서 왜 인가했는데, 문제 자체가 이해가 어려워서였던 것 같다. 괜히 원을 만든다는 가정이 문제를 이해하기 어렵게 했다. 근데 문제 자체를 이해하고 나니 풀이는 재미있었다.
특히 match메소드를 이용해서 null이 나오는데 배열의 length 프로퍼티로 비교하려고 하려면 어떻게 처리해야할까 고민했는데, || 논리 연산자를 이용해 match 메소드에서 null이 나오면 변수에 빈배열이 대입되도록 처리했다. 두번째 풀이의 삼항연산자에 쓴 것과 같이 &&||같은 논리 연산자의 특성을 활용해보니 코드가 굉장히 깔끔해보여서 기분이 좋았다.

Share Comments

Hamming Distance

leetcode 문제링크

The Hamming distance between two integers is the number of positions at which the corresponding bits are different.

Given two integers x and y, calculate the Hamming distance.

Note:

  • 0 ≤ x, y < 231.

Example:

  • Input: x = 1, y = 4
  • Output: 2

Explanation:

1
2
3
1   (0 0 0 1)
4 (0 1 0 0)
↑ ↑

The above arrows point to positions where the corresponding bits are different.

나의 풀이

해밍거리(Hamming Distance)
블록 부호 이론에서, 해밍 거리(Hamming距離, 영어: Hamming distance)는 곱집합 위에 정의되는 거리 함수이다. 대략, 같은 길이의 두 문자열에서, 같은 위치에서 서로 다른 기호들이 몇 개인지를 센다.

주어진 값들을 이진수 형태에서 비교해서 같은 위치에 다른 수가 몇개인지를 세면 되는 것 같다. 이진수로 바꾸는 방법은 toString 메소드를 사용했고, 수에 따라 같은 길이가 아닐 수 있으니 뒤의 수부터 비교해주기로 했다.
sort를 이용해 길이가 긴 수를 정해서 reduce를 통해 그 길이에 수가 둘 다 있으면 두 수(문자)를 비교해 다르면 누적에 1을 더하고 만약 위치에 수가 없으면 수가 있는 배열의 값이 ‘1’일 경우 더한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
// 56 ms
var hammingDistance = function(x, y) {
const arr = [x.toString(2).split('').reverse(), y.toString(2).split('').reverse()].sort((a, b) => b.length - a.length);
return arr[0].reduce((acc, item, index, array) => {
if(arr[1][index] && arr[1][index] !== item) {
return acc + 1
} else if (!arr[1][index] && item === '1') {
return acc + 1
} else {
return acc
}
}, 0)
};

다른 사람 풀이

이걸 한 줄로 푸네…

1
2
3
4
// 60ms
var hammingDistance = function(x, y) {
return (x ^ y).toString(2).split('0').join('').length;
};

1. ^(Bitwise XOR)

^부분이 이해가 안되었는데 XOR이라는 연산자로 다음의 표와 같이 a와 b가 다른 경우 1을 산출한다고 한다.

a b a XOR b
0 0 0
0 1 1
1 0 1
1 1 0

비트 연산자는 피연산자를 10진수나 16진수나 8진수와 같은 숫자가 아니라, 32비트(0과 1)의 집합으로 표현한다.

1
2
3
4
.    9 (base 10) = 00000000000000000000000000001001 (base 2)
14 (base 10) = 00000000000000000000000000001110 (base 2)
--------------------------------
14 ^ 9 (base 10) = 00000000000000000000000000000111 (base 2) = 7 (base 10)

그렇다면 위의 풀이에서 x, y 간의 배타적 논리합을 구해서 그 수의 이진수 표현(문자열) 중 문자 ‘0’을 제거하면(split(‘0’)) ‘1’만 남게 되는 데 이 1은 x, y가 같은 위치에 다른 문자였음을 의미하니까 그 길이를 구하면 원하는 결과를 얻을 수 있다.


다만, 왜 이 풀이가 내 풀이보다 느린 지 아직 잘 모르겠다. 처음에는 32비트 집합간의 비교라서 그런건가 했는데 비트가 더…느릴 수…있나? 왠지 환경에 따라 다를 것 같은 미미한 차이라…

Share Comments

flip And Invert Image

leetcode 문제링크

Given a binary matrix A, we want to flip the image horizontally, then invert it, and return the resulting image.

To flip an image horizontally means that each row of the image is reversed. For example, flipping [1, 1, 0] horizontally results in [0, 1, 1].

To invert an image means that each 0 is replaced by 1, and each 1 is replaced by 0. For example, inverting [0, 1, 1] results in [1, 0, 0].

Example 1:

  • Input: [[1,1,0],[1,0,1],[0,0,0]]
  • Output: [[1,0,0],[0,1,0],[1,1,1]]
  • Explanation: First reverse each row: [[0,1,1],[1,0,1],[0,0,0]].
  • Then, invert the image: [[1,0,0],[0,1,0],[1,1,1]]

Example 2:

  • Input: [[1,1,0,0],[1,0,0,1],[0,1,1,1],[1,0,1,0]]
  • Output: [[1,1,0,0],[0,1,1,0],[0,0,0,1],[1,0,1,0]]
  • Explanation: First reverse each row: [[0,0,1,1],[1,0,0,1],[1,1,1,0],[0,1,0,1]].
  • Then invert the image: [[1,1,0,0],[0,1,1,0],[0,0,0,1],[1,0,1,0]]

Notes:

  • 1 <= A.length = A[0].length <= 20
  • 0 <= A[i][j] <= 1

나의 풀이

문제를 요약하면 0과 1로만 이루어진 2차원 배열을 수평으로 한번 뒤집고, 0은 1로 1은 0으로 치환되면 된다.
이미지 파일을 뒤집는 방법이 이런식으로 이루어지나 보다.

1
2
3
4
5
6
7
8
9
10
11
// 72 ms
var flipAndInvertImage = function(A) {
const arr = A;
for (let i = 0, l = arr.length, n = arr[0].length; i < l; i++) {
arr[i].reverse();
for (let j = 0; j < n; j++) {
arr[i][j] = arr[i][j] === 1 ? 0 : 1;
}
}
return arr;
};

2차원 배열이니 for문을 2번 썼다.
for문을 두번 쓰는 다음과 같은 경우에는 적절한 것 같은데, reverse가 원본 배열을 바꾸는 메소드이고 arr[i][j]에 값을 대입하는 부분 역시 원본 배열에 변화를 주기 때문에 만약에 원본 배열에 영향을 주고 싶지 않다면 깊은복사를 할 수 있도록 고려해야 될 것 같다.

그렇다면 다음과 같은 방법을 사용하면 인자로 넘겨지는 원본 배열에 변형 없이 새로운 배열을 얻을 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
// 68 ms
var flipAndInvertImage = function(A) {
const newArr = [];
for (let i = 0, l = A.length, n = A[0].length; i < l; i++) {
const newRow = A[i].concat().reverse();
for (let j = 0; j < n; j++) {
newRow[j] = newRow[j] === 1 ? 0 : 1;
}
newArr.push(newRow);
}
return newArr;
};

또 다른 방법으로 for of 문을 쓰면서 map 메소드를 사용하는 방법을 써봤다.

1
2
3
4
5
6
7
8
9
// 64 ms
var flipAndInvertImage = function(A) {
const newArr = [];
for (const i of A) {
const newRow = i.concat().reverse().map(item => item === 1 ? 0 : 1)
newArr.push(newRow);
}
return newArr;
};

다른 사람 풀이

map을 두번 써서 풀었다. 그런데 이 풀이도 만약에 원본 배열을 바꾸고 싶지 않다면 reverse() 메소드 이전에 복사하는 부분이 없기 때문에 변형이 생긴다.

1
2
3
var flipAndInvertImage = function(A) {
return A.map(row => row.reverse().map(num => num ? 0 : 1))
};

Share Comments

Jewels and Stones

leetcode 문제링크

You’re given strings J representing the types of stones that are jewels, and S representing the stones you have. Each character in S is a type of stone you have. You want to know how many of the stones you have are also jewels.

The letters in J are guaranteed distinct, and all characters in J and S are letters. Letters are case sensitive, so “a” is considered a different type of stone from “A”.

Example 1:

  • Input: J = “aA”, S = “aAAbbbb”
  • Output: 3

Example 2:

  • Input: J = “z”, S = “ZZ”
  • Output: 0

Note:
S and J will consist of letters and have length at most 50.
The characters in J are distinct.

나의 풀이

오랜만에 풀려니 머리가 잘 굴러가지 않는데 그럴땐 일단 가장 단순 무식한 방법으로 (Brute force 식으로) 풀어버리는 게 가장 좋은 것 같다.

1
2
3
4
5
6
7
8
9
10
11
12
// 60ms
var numJewelsInStones = function(J, S) {
let num = 0;
const jArr = J.split('');
const sArr = S.split('');
for (let i = 0, l = jArr.length; i < l; i++) {
for (let j = 0, m = sArr.length; j < m; j++) {
sArr[j] === jArr[i] && num++;
}
}
return num;
};

아니 근데 반복문 2번은 돌려야 풀 수 있는 문제네;;

1
2
3
4
5
6
7
8
9
10
// 64ms
var numJewelsInStones = function(J, S) {
let num = 0;
for (const i of J) {
for (const j of S) {
j === i && num++
}
}
return num;
};

다른 사람 풀이

reduce 메서드를 이용한 방법

1
2
3
4
5
6
7
8
9
10
// 52ms
var numJewelsInStones = function(J, S) {
const jewels = J.split('');
return S.split('').reduce(function(a, b) {
if(jewels.includes(b)) {
a += 1;
}
return a;
}, 0)
}

Share Comments

TIL 20180624

오늘 한 일

파이널 프로젝트

  • 팀 명: geek-ryan
  • 프로젝트 명: seemva

Ant Design 테스트

리액트 컴포넌트로 제공하거나 form 같은 경우 verify 해주는 부분의 가이드를 제공해준다. 나중에 만들어 볼지도 모를 calendar컴포넌트도 제공하고, airbnb의 datapicker를 사용하려고 했었는데, 이 역시 컴포넌트로 제공하고 있다. timeline 컴포넌트는 프로젝트에서 쓰려고 하는 것과 맞지 않아서 아쉽지만…
각자 테스트 해본 뒤 방향을 결정하기로 했는데, 논의 끝에 우선 이 디자인 컴포넌트를 이용해 보기로 했다.

와이어프레임

각자 벤치마킹을 해보고 와이어프레임을 그려보기로 했다. 논의는 트렐로를 통해 이루어졌다. 벤치마킹한 사이트의 이미지나 링크를 트렐로를 통해 공유하고, 팀원이 손그림으로 와이어프레임을 그린 것을 트렐로에 올린 것을 카카오 oven을 통해 정리했다.
로그인, 회원가입, 보드 화면까지만 만들었는데, 한꺼번에 하기보다는 먼저 컴포넌트별, 페이지별로 개발을 들어가면서 수정하고 추가하는 식으로 진행하는 것이 좋을 것 같다.

  • 로그인, 회원가입: chiabi
  • 보드화면, 보드의 사이드바: akiraei

네이밍 컨벤션

예. Login form

directory : filename

  • components: UserFormButtonPC.js
  • containers:UserFormButtonCC.js
  • contexts: UserFormCTX.js
  • pages: LoginPage.js
  • hocs: withAuth.js
  • serverAPI.js

※ components 파일에서 PC 작성시 반드시 storybook 파일 남길 것
UserFormButtonPC.stories.js

※ 되도록 축약 표현이 아닌 풀 네임으로 만들것 (Btn(x), Button(o))

앞으로 사용 예정인 라이브러리

프로필 부분은 고민이다. 사진을 올릴 수 있어야하는데, 이미지 서버를 따로 두는 방법을 고민 중이다. 이부분을 내가 테스트해보기로 해서 로그인과 회원가입 부분을 맡기로 했다.

Share Comments

TIL 20180622

오늘 한 일

1. 프론트엔드 개발 스쿨

강사님이 게시판 게시글 CRUD와 댓글은 보여주는 것 까지만 구현하신 코드를 보면서 설명해주셨다.
코드를 보니 또 내가 생각한 것과는 context 설계가 달랐다. 나는 post 폼은 PostListContext.js(componentDidMount 훅에 서버로 포스트 리스트에 대해서 GET 요청을 보내는 부분이 있는)에 서버에 POST하는 메소드를 추가해서 post 폼 컨테이너로 내려보내고, 나중에 post 폼 수정 페이지에서는 PostContext.js(componentDidMount 훅에 서버로 특정 포스트에 대해서 GET 요청을 보내는 부분이 있는)에 PATCH 요청을 보내는 메소드를 추가해서 내려보내는 식으로 해서 context를 같이 사용하려고 했는데, 강사님은 폼 추가/삭제에 대한 context를 따로 만들어서 id가 있을 경우에 따라 조건문을 통해 componentDidMount 훅에서 특정 포스트에 대한 GET 요청을 보내는 식으로 구현하셨다.
그리고 내가 간과하고 있던 것이 나는 게시글 추가 시에 게시판 목록으로 Redirect를 걸었는데 생각해보니 사용자의 관점에서는 게시글 목록이 아니라 생성된 게시글의 보기 페이지로 Redirect를 걸어주는 게 맞는 것 같다.

그리고 페이지는 함수형 컴포넌트로 만들었는데, 그러면서 화살표 함수로 만들면서 익명함수로 만든게 개발자 도구에서는 Unknown으로 보인다는 것도 알게 되었다. 그리고 Router부분을 나는 이슈 페이지에서 찾은 코드를 추가했는데, storybook-react-router라는 라이브러리가 있어서 그걸 쓰면 더 간략한 코드로 내가 처리한 부분을 대체할 수 있었다.

나는 Components 디렉터리의 PC 컴포넌트에서 username이나 password 상태를 관리하고 Context의 메소드를 내려받아서 핸들링해줬는데, 강사님은 Container에서 처리해주셨다. 이부분은 따로 여쭤봤는데, 물론 PC에서 관리해도 그것은 어떻게 설계하느냐(말하자면 관리 정책 측면이라)에 따른 거라 문제 될 것은 없지만, 로그인의 경우 사용자 입력을 받아 서버에 요청을 보내고 성공했는지에 따라 success 상태를 토글해서 Redirect를 걸어준다면 그 부분은 외부와 연동되는 부분이 들어가게 되니까 CC에서 처리하는 게 좋을 거라고 생각했다고 하셨다.

2. 파이널 프로젝트 회의

파이널 프로젝트로 쇼핑몰을 할 지 기존에 템플릿으로 만들어봤던 프로젝트 관리 서비스를 만들지 고민했다. 팀원이랑 의논 끝에 기존에 만들어본 프로젝트 관리 서비스를 하는 대신에 규모를 더 키워보기로 했다. 이전에는 사용자의 프로젝트 todo 리스트에 가까웠다면 이번에는 아예 팀 별로 프로젝트를 생성해서 관리할 수 있는 트렐로, asana 같은 서비스를 만들어보기로 했다.(물론 그들이 제공하는 모든 기능을 구현할 수는 없겠지만) 그리고 라이브러리를 이용해 타임라인과 캘린더 보기까기 구현해보기로 계획했다.
오늘 강사님이 알려주신 eslint와 prettier 설정으로 코딩 스타일은 얼추 맞출 수 있게 되었고, 구체적으로 설계하는 부분은 같이 맞춰나가기로 했다. 기능단위로 PC를 먼저 구현한 뒤에 일단 Context를 만들어 상태를 관리하고 Context에서 보관할 필요가 없는 상태라면 CC에서 처리해주기로 했다.

오늘은 일단 프로젝트를 어느정도 규모로 할 지와 나중에 수정할지라고 일단 컴포넌트 작성 순서와 상태 관리를 어디에서 할 건지 먼저 정하고, 내일은 일단 어느정도 와이어프레임을 위해 각자 벤치마킹을 해보고 일요일까지 와이어프레임을 만든 뒤 기능 별 분담을 하기로 했다.

2주내에 다 할 수 있을까 조금 걱정이 되긴 하는데, 만드는 것은 재미있을 것 같다. 목표한대로 1주 정도는 전체적으로 만들고 남은 기간에는 스타일링과 코드 개선을 할 수 있으면 좋겠다.

내일 할 일

  • 파이널 프로젝트 와이어프레임을 위한 벤치마킹
  • 강사님 게시판 코드 읽어보고 연습하기
  • Ant Design 써보기
Share Comments

TIL 2018021

오늘 한 일

1. 리액트로 게시판 만들기

다 완성하고 싶었는데, 오류도 잡고 어떻게 만들어야할까 고민하다보니 댓글까지는 넣지 못했다.
원래는 PostList와 Post Context로 분리하지 않고 Post Context 하나로 모든 상태를 같이 관리하려고 했는데, 강사님이 보여주신 코드를 보니 list와 view에서 쓸 수 있는 Context를 따로 나누셨다. 왜 그렇게 하셨을까 생각을 해보니 나는 어차피 post를 모두 불러오니까 그걸로 filter메소드 등을 써서 특정 id의 post를 찾으면 되지 않을까라고 생각했는데(뷰페이지는 그렇게 만들기까지 했었다.), 새 글 작성은 몰라도 글을 수정하는 페이지를 어떻게 처리할 건가 생각해보니 componetDidMount시에 보내는 요청이 다르기 때문에 따로 context를 분리하는 게 더 나을것 같아서 수정했다.
router 사용시 ‘/post’(리스트) ‘/post/write’(새 글 작성), ‘/post/1’(뷰페이지) 이렇게 주소가 표시되도록 하려고 했는데, write 페이지가 렌더링 되지 않았다. 이유는 ‘/post/write역시 ‘/post/:postId’ Route에 걸리기 때문이었다. ‘/post/write’ Route에 exact를 추가하고 위로 올리니 해결되었다.
그 다음 문제는 write페이지에서

1
GET https://{server}/posts/write?_expand=user 404 ()

이런식으로 404에러를 던지고 있는데, 왜 저런식으로 요청을 보내나했더니 처음에는 <Route><Switch>로 둘러줬다가 exact를 쓰니까 제거해도 되지 않을까 했는데, 그렇게 되면 write일때도 걸리고 post의 params로도 걸려서 뷰페이지도 렌더링 되고 있었다. 다시 <Switch>로 둘러줘서 하나의 Route만 걸리도록 했더니 해결되었다.
스토리북에서 테스트하는 컴포넌트에 react router의 컴포넌트 사용으로 오류가 자꾸 발생되었는데, 이부분은 찾아보니 스토리북 깃헙에 이슈로 올라와 있었다. addDecorator를 이용한 해결방법도 찾을 수 있었다.

내일 할 일

  • 파이널 프로젝트 기획하기
Share Comments

TIL 20180620

1. 프론트엔드 스쿨과정 - 리액트

  • HOC로 인증 관련 문제 해결하기
  • defaultProps
  • Sass 사용하기
  • classnames
  • 규모있는 프로젝트의 개발 순서는 어떻게 가져가야 할까?

Sass 사용은 visual studio code에서 바로 컴파일 해주는 익스텐션을 사용하도록 알려주셨는데, 시간이 나면 webpack을 이용하는 방법을 알아봐야겠다.

2. 리액트로 게시판 만들기

기본적인 로그인 구현까지했다. 스토리북을 이용해서 Presentational 컴포넌트를 먼저 확인하면서 만들고 있다. 만들다가 기억이 잘 안나는 부분은 다시 todo 실습으로 돌아가서 참고하고 있는데, rgb 챌린지처럼 먼저 단순하게 만들고 더 다듬어야 될 것 같다. 아직 어느 코드가 중복되는 로직일지 파악할 수 없어서 오늘 배운 HOC은 적용해보지 못했는데, 다듬다보면 어느때 써야할 지 감이 잡힐 것 같다. 이번 과제로 게시판을 한번 만들어보면 마지막 과제를 할 때 많은 도움이 될 것 같다.

내일 할 일

  • 리액트로 게시판 만들기 과제 완료하기
    • 로그인
      • 데이터설계(json server)
      • presentational: 로그인 화면
      • Provider: 상태관리
      • Container 컴포넌트 (PC와 Provider를 이어줄)
    • 글 목록
    • 글 작성
    • 댓글 목록
Share Comments

TIL 20180619

오늘 한 일

1. 프론트엔드 스쿨과정 - 리액트

  • Provider의 적절한 위치는?
  • 마운트되었을 때 부작용을 일으키는 컴포넌트 (OnMount 컴포넌트)
  • 브라우저의 중요한 UI - 주소표시줄, hash, 새로고침, 뒤로가기, 앞으로가기
  • HTML5 history API & hashchange
  • react-router 소개 및 실습

‘만약 단순한 모달 정도가 아니라 페이지가 이동되는 것 같이 느껴지도록 만들려면 리액트로 어떻게 해야하지?’ 라는 고민이 해결되었다. 리액트 라우터를 통해 굉장히 쉽게 구현할 수 있었다. 강사님께서 리액트 라우터에 대해 설명하기 전에 마운트되었을 때 부작용을 일으키는 컴포넌트나 history객체, pushState 같은 바탕이 되는 개념을 먼저 설명해주셔서 덕분에 크게 어렵게 느껴지지 않았다.
리액트 라우터를 배우고 나니 파이널 프로젝트에서는 쇼핑몰을 도전해보고 싶어졌다.

2. rgb 챌린지 게임 수정

강사님이 코드 리뷰를 해주신 것을 토대로 다시 수정했다. 컬러 코드, 스테이지, 점수 등이 서로 결합되어 있기 때문에 GameContext라는 하나의 컴포넌트에서 모든 상태를 관리하는 방법으로 해볼 것을 조언해주셔서 ColorContext와 ResultContext, ScoreContext로 나눴던 것을 GameContext로 합쳤다. 그리고 GameConsumer를 사용하게 되는 부분은 Container 컴포넌트로 따로 만들었다.
컴포넌트가 너무 많은것이 아닌가 걱정이었는데, context 컴포넌트를 줄였음에도 Presentaional 컴포넌트와 Container 컴포넌트로 분리해보려고 했더니 컴포넌트가 많아졌다.
어쩌면 내가 잘못 쓰고 있는 건 아닌지;;
강사님이 번역해주신 dan Abramov의 아티클을 다시 읽어봤는데, 잘 사용하고 있는지 아직은 개념이 어렵게 느껴진다. 내일 또 여쭤봐야겠다.

내일 할 일

  • 리액트 미니 프로젝트 - social card 만들기(트위터 참고)
  • 자기소개서 최종 검토하기
Share Comments