어제부(10/8)로 길다면 길고 짧다면 짧은 일주일의 과제 심화주차 기간이 끝나고 회고의 날이 찾아왔다. 아쉬움보다는 앞으로의 항해를 어떻게 이어갈지를 생각하며 내가 속한 팀인 23조 및 다른 팀의 항해원들이 남긴 Wrap-up Assignment (W.A.)을 질문별로 찬찬히 살펴보는 시간을 가져보았다.
각 팀당 두 가지 질문을 스스로 만들어서 답변해 보세요 :-)
[23조]
우리 팀은 Debounce와 Throttle의 차이 & Memoization에 대한 질문을 만들었음.
이벤트 요청을 받으면 정해진 시간 만큼 기다렸다가 실행.
단, 실행 전 새로운 수행 요청이 들어오면 이전 요청을 실행하지 않고 새로운 요청을 실행함.
정해진 시간동안 들어온 요청을 취합하여 실행하기를 반복함.
ex)
import _ from "lodash";
...
const debounce = _.debounce((e)=>{
console.log("debounce:::", e.target.value);
},1000} //새로운 요청이 들어오지 않으면 1초후 input 안에 들어온 값을 출력
const throttle = _.throttle((e)=>{
console.log("throttle:::", e.target.value);
},1000} //1초마다 input에 들어온 값을 출력
const onchange = (e) => {
debounce(e);
throttle(e);
}
...
return <input type="text" onChange={onchange}/>
예를 들어 "감자는 맛있다." 라는 문구를 입력창에 입력하면 onChange
로 인해 문자가 입력될때마다 요청이 발생함. 이 때 throttle
은 1초마다 지금까지 입력된 값을 출력하고 debounce
는 문장 입력이 끝나고 1초 후 출력함.
Memoization은 주어진 입력값에 대한 결과를 저장함으로써 같은 입력값에 대해 함수가 한 번만 실행되도록 함. 예를 들어 n번째 피보나치 수를 계산하는 아래의 간단한 재귀식을 보면, 입력값에 대해 여러 번 실행되는 것을 알 수 있음.
deffib(n):
if n< 0:
raise IndexError(
'Index was negative.'
'No such thing as a negative index in a series.'
)
elif nin [0, 1]:
# Base cases
return n
print("computing fib(%i)"% n)
return fib(n- 1)+ fib(n- 2)
위 함수의 재귀호출은 빠르게 가지를 뻗어가는 트리 형태로 상상해볼 수 있음. 노드의 두 자식들은 노드가 만들어내는 두 재귀호출이 됨.
그리고 이처럼 가지를 뻗어나감으로써 발생되는 반복 작업을 피하기 위해서는, 입력값을 출력값과 매핑해주는 memo 라는 속성을 가진 클래스로 함수를 감싸야함.
이러한 과정을 통해,
memo
를 체크함으로써 어떤 주어진 입력값에 대해 계산을 안 해도 되는지 확인가능함memo
에 저장할 수 있음.classFibber(object):
def__init__(self):
self.memo= {}
deffib(self, n):
if n< 0:
raise IndexError(
'Index was negative.'
'No such thing as a negative index in a series.'
)
# Base cases
elif nin [0, 1]:
return n
# 이미 계산한 값인지 아닌지 확인한다.
elif nin self.memo:
print ("grabbling memo[%i]"% n)
return self.memo[n]
print("computing fib(%i)"% n)
result= self.fib(n- 1)+ self.fib(n- 2)
# Memoize
self.memo[n]= result
return result
이제 아래의 재귀 트리에서, 노드는 두 번 이상 나타나지 않음.
Memoization(메모이제이션)은 dynamic programming(동적 계획법) 문제를 풀 때 흔히 쓰이는 방법임. 동적 계획법이란 문제의 정답이, 입력값의 더 작은 부분에 대해 동일한 문제의 정답으로 구성되어 있는(마치 위에서 설명한 피보나치 같은 문제) 문제를 의미함. 동적 계획법 문제를 풀기 위한 또다른 일반적인 방법은 Bottom-up이 있는데, 보통 이것이 더 깔끔하고 더 효율적임.
[18조]
▶ 파라미터란?
특정 id나 이름을 가지고 조회를 할 때 사용하게 되고, 쿼리의 경우는 어떤 키워드를 검색하거나 요청할 때 필요한 옵션을 전달 할 때 사용됨. 파라미터는 일반적으로 특정id나 이름을 가지고 조회할때 사용함. 그 방법으로는 리액트의 라우팅 라이브러리를 사용해 (react-router-dom) Match 객체 에 접근하여 URL 파라미터를 받아올 수 있음.
<Route path="/somepath/:someInfo" component={SomeComponent}/>
이렇게 path에 파라미터를 추가할 수 있고, 여기에 http://localhost:3000/somepath/Hello와 같은 요청을 받게 된다면 param 값은 {someInfo: "Hello"} 가 됨. 이를 원하는 페이지 에서 match를 받아와 match.params.seomInfo를 출력하면 Hello가 나옴.
▶ 디바운스란?
이벤트가 일어나면 일정시간 기다렸다가 이벤트를 수행하는 것. onChange 이벤트에서 키값 하나하나를 입력할 때마다 api 콜을 날리면 서버부담을 줄 수 있으므로 그것을 막기위해 하는 것.
- 예시
- ㄱ | 가 | 감 |1초| 감ㅅ | 감사 | 감샇 |2초|
- 이렇게 검색한다고 했을때 이벤트에서 ㄱ, 가 이벤트는 삭제하고 미지막 이벤트를 실행함.
- 활용사례
- 연관검색어
- 감사합니다 검색한다고 했을 때 가나 감사합 검색어는 필요없음.
- 이전 이벤트 삭제해도 괜찮은 예시가 적합함.
[22조]
▶ 옵셔널 체이닝이란?
Optional Chaining은 ES2020에서 등장한 새로운 연산자로서 '?.' 의 형태로 사용하며 체인으로 이루어진 각 참조가 유효한지 명시적으로 검증하지 않고 연결된 객체 체인 내에 깊숙히 위치한 속성 값을 읽을 수 있는 연산자임.
호이스팅에 대하여
https://endurable-existence-f23.notion.site/023f2e154d7148ffa7c9dfb9ed1f4ca7
s3 버킷에 배포한 뒤, 어떤도메인.com이 아닌 어떤도메인.com/login 등 페이지로 이동하면 왜 오류가 날까요?
▶ 참고
https://docs.aws.amazon.com/ko_kr/AmazonS3/latest/userguide/CustomErrorDocSupport.html
[15조]
리액트는 SPA 이기 때문에, 배포하게되면 S3서버에서는 index.html파일 하나만 있다고 인식하여, /login 이렇게 direct로 접근하게 되면 Access denied가 뜨게됨. (따로 옵션을 해줘야..)
[18조]
아마존 S3에서 /login 페이지를 존재하지 않는 객체 키를 참조 한다고 판단하고 url에 지정된 버킷이 존재하지 않는 것으로 간주되어 생기는 문제.
[튜터님의 답변]
리액트에서 각 페이지 컨텐츠에 맞는 미리보기(사이트 이미지, 사이트 설명 등)를 띄워주려면 어떻게 해야할까요?
생성자 객체를 생성함.
const reader = new FileReader()
이벤트 핸들러
reader.onload = () => {}
FileReader.readAsDataURL()
특정 Blob이나 File에서 읽어 오는 역할을 함. 다 읽고 난후 result 속성에 결과가 담아짐. - readAsDataURL() MDN 참조
Blob객체란? 파일류의 불변하는 미가공 데이터를 의미함.
1) react-helmet 설치하기
yarn add react-helmet
2) helmat으로 메타 태그 바꾸기
//One.js
import React from "react";
import {Helmet} from "react-helmet";
const One = (props) => {
return (
<div>
<Helmet>
<title>page one</title>
<meta property="og:title" content="page one" />
<meta property="og:description" content="hi there :) page one" />
<meta property="og:image" content="%PUBLIC_URL%/logo192.png" />
</Helmet>
<h2>Hi, there :) ! page one</h2>
<button
onClick={() => {
props.history.push("/");
}}
>
page one
</button>
<button
onClick={() => {
props.history.push("/two");
}}
>
page two
</button>
</div>
);
}
export default One;
3) 확인하기
빌드 후, post man에서 확인해보기
yarn build
ex)
https://www.notion.so/React-W-A-23-7aa86bba589f457bab8c5de7c90d36a4#e8cf5e87799c48bc962bb89e8fd1a511
[15조]
⚙️ SPA
한개의 페이지를 가진 어플리케이션
SPA는 클라이언트 사이드 렌더링이지만 SPA === CSR
<장점>
사용자 친화적
초기 렌더링 후 데이터만 받아오기 때문에, 상대적으로 서버 요청이 적음.
⚙️ CSR
최초 요청시 html을 비록해 CSS, Javascript 각종 리소스를 받아옴.
서버에 데이터만 요청하고, 자바스크립트로 뷰를 컨트롤함.
초기요청에서 SSR 보다 많은 리소스를 요청하기 때문에 SSR보다 느림.
하지만 이후 다른페이지로 이동시 SSR보다 빠른 전환속도로 더 나은 사용자 경험을 제공.
🔨 검색엔진
검색엔진들은 웹사이트의 올려진 html을 분석해서 (여기에는 이런 title과 이런 컨텐츠가 있으니깐 특정 검색어로 찾아질수 있는 사이트라고) 검색엔진에 올려놓음.
🔨 react-helmet 이란?
리액트 SPA방식이고 index.html 하나만 존재함.
크롤러가 그 페이지를 읽으면 빈 index.html(컨텐트가 없다고) 만 있다고 인식함. 이것을 해결하기 위해 react-helmet 라이브러리를 통해 meta-tag를 넣어줘서 검색엔진 최적화에 조금이나마 도움이 됨.
🔨 어떻게 해야할까요?
각 컴포넌트에 helmet을 이용해서 meta 태그를 넣어줌.
[튜터님의 답변]
리덕스에서 미들웨어 청크의 역할은 뭘까요?
리덕스에서 비동기 처리를 할 때 가장 많이 사용되는 미들웨어로 액션객체가 아닌 함수를 디스패치 할 수 있음.
일반 액션 생성자는 하나의 액션객체를 생성하는 반면, redux-thunk를 통해 만들어진 액션 생성자는 내부에서 여러가지 작업 가능.
thunk 함수를 만들어 dispatch 하면 미들웨어가 그 함수를 전달받아 dispatch와 getState를 파라미터로 넣어서 호출.
redux-thunk 형태
const reduxTunck = () => (dispatch, getState) =>{ }
[15조]
🔨 미들웨어란?
기본 리덕스만 쓰게되면 동기 작업밖에 안됨. 비동기 작업(서버에 요청 응답, 외부 API 연동)를 사용하기위해 middleware에서 처리함.
🔨 redux-thunk
redux-thunk 미들웨어의 한종류.
redux-thunk는 액션 creator가 액션 대신 thunk라는 함수를 반환함.
기존 리덕스에서는 객체만을 반환하는데, redux-thunk라는 미들웨어를 사용하면 함수를 반환하게되고 그 안에서 비동기작업을 할 수 있음.
[24조]
redux-thunk는 리덕스에서 비동기 작업을 처리 할 때 가장 많이 사용하는 미들웨어임. redux-thunk 라는 미들웨어를 사용하며 이 미들웨어를 사용하면 액션 객체가 아닌 함수를 디스패치 할 수 있음.
thunk는 특정 작업을 나중에 하도록 미루기 위해서 함수형태로 감싼것을 칭함. 코드가 실행 될 때 바로 이뤄지지 않고 foo() 가 호출 되어야만 이루어짐.
[튜터님의 답변]
액션 객체를 dispatch하는 대신 함수를 dispatch할 수 있도록 해줌.
dispatch한 함수는 dispatch, getState, 그 외의 직접 설정한 값을 받아 사용할 수 있음.
비동기 처리 등에 사용할 수 있음.
프로미스는 정확히 말하면 비동기가 아닙니다. 비동기와 프로미스는 각각 무엇일까요?
비동기와 Promise의 가장 큰 차이점은 비동기는 데이터 처리 방식이고 Promise는 객체라는 점.
비동기란 여러가지의 작업이 각자 끝나는 대로 바로 처리되는 병렬적 데이터 처리 방식. 따라서 작업을 요청하고 그 결과를 꼭 바로 받지 않고 다른 작업을 수행할 수 있음.
Promise란 비동기 작업의 결과를 나타내는 JavaScript 객체. 즉, JavaScript 상에서 비동기적으로 실행되는 작업의 결과 (성공 또는 실패)를 객체화하여 반환함.
Promise 상태값
pending : 비동기 처리 수행 전
fulfillde : 수행 성공
rejected : 수행 실패
settled : 성공 or 실패
[18조]
비동기는 동시에 여러 가지 작업을 할 수 있는 개념이고 Promise는 비동기 작업의 단위를 뜻하며 비동기 작업을 쉽게 관리할 수 있음.
[19조]
▶ 비동기 처리란?
어떤 작업을 요청했을 때 그 작업이 종료될때 까지 기다리지 않고 다른 작업을 하고 있다가, 요청했던 작업이 종료되면 그에 대한 추가 작업을 수행하는 방식.
▶ 프라미스란?
비동기 작업이 종료된 후 결과값이 어떠한지에 대해 반환을 약속해주는 객체.
[튜터님의 답변]
TDZ(Temporal Dead Zone/일시적 사각지대)란?
let이나 const 선언후 초기화 전에 할당을 하는 코드
**// Temporal Dead Zone**
A; // ReferenceError
const A = 1;
A; // 1
[15조]
🔨 TDZ
스코프의 시작 지점부터 초기화 시작 지점까지의 구간을 TDZ(Temporal Dead Zone) 라고 함.
[14조]
일시적인 사각지대는 스코프의 시작 지점부터 초기화 시작 지점까지 구간을 TDZ(Temporal
Dead Zone)이라고함.
우리가 변수를 입력하면,
우리가 변수를 입력할때 var혹은 let/const를 그냥 사용하였지만사실은 위 3가지 단계를 거쳐서 생성되는 것.
[튜터님의 답변]
const, let을 선언할 때 선언 -> 초기화 단계를 거침. 런타임(파일을 한 줄 한 줄 실행하는 것) 이전에 선언되어 메모리에 한 자리를 차지하지만 초기화 단계가 아직 실행되지 않았기 때문에 해당 변수(상수)에 접근할 수는 없는 상태를 TDZ라고 함.