23일) 브라우저에도 저장공간이 있대!.. localStorage/Next.js 렌더링의 Diffing / Hydration/권한분기/Closure/HOC / HOF code camp fe 6기
- 오늘의 알고리즘 문제
'어려움' 문제를 내가 스스로 생각해서 처음 맞췄다!!!!!!!!!!!!!!!
오늘 등원할때 궁둥이에 찝찝한게 묻어서 기분이 안좋았었는데 문제 잘푸려고 그랬나보다. 너무너무 행복하다 !
알고리즘 풀이접근법을 잘 몰랐던 내가 이렇게 발전할 수 있는 이유는
세준멘토님이 알려주신 정답에 접근하는 법을 적용했기 때문이다.
1.RunJS를 켜서 실시간으로 값을 확인하며 풀것
2.주어진 값들을 확인하고 어떻게 가공해야하는지 콘솔로 계속 찍으며 생각할것
3.도출하는 값의 타입을 확인하면서 적절한 메서드를 쓸것
이 전에는 사실 귀찮아서(?) 콘솔도 잘 안찍어가며 runjs만 겨우 돌렸는데,
알고리즘 마스터가 될거야 !!!!!!!!!!
-오늘의문제
당신은 폰켓몬을 잡기 위한 오랜 여행 끝에, 홍 박사님의 연구실에 도착했습니다. 홍 박사님은 당신에게 자신의 연구실에 있는 총 N 마리의 폰켓몬 중에서 N/2마리를 가져가도 좋다고 했습니다.
홍 박사님 연구실의 폰켓몬은 종류에 따라 번호를 붙여 구분합니다. 따라서 같은 종류의 폰켓몬은 같은 번호를 가지고 있습니다. 예를 들어 연구실에 총 4마리의 폰켓몬이 있고, 각 폰켓몬의 종류 번호가 [3번, 1번, 2번, 3번]이라면 이는 3번 폰켓몬 두 마리, 1번 폰켓몬 한 마리, 2번 폰켓몬 한 마리가 있음을 나타냅니다. 이때, 4마리의 폰켓몬 중 2마리를 고르는 방법은 다음과 같이 6가지가 있습니다.
첫 번째(3번), 두 번째(1번) 폰켓몬을 선택
첫 번째(3번), 세 번째(2번) 폰켓몬을 선택
첫 번째(3번), 네 번째(3번) 폰켓몬을 선택
두 번째(1번), 세 번째(2번) 폰켓몬을 선택
두 번째(1번), 네 번째(3번) 폰켓몬을 선택
세 번째(2번), 네 번째(3번) 폰켓몬을 선택
이때, 첫 번째(3번) 폰켓몬과 네 번째(3번) 폰켓몬을 선택하는 방법은 한 종류(3번 폰켓몬 두 마리)의 폰켓몬만 가질 수 있지만, 다른 방법들은 모두 두 종류의 폰켓몬을 가질 수 있습니다. 따라서 위 예시에서 가질 수 있는 폰켓몬 종류 수의 최댓값은 2가 됩니다.
당신은 최대한 다양한 종류의 폰켓몬을 가지길 원하기 때문에, 최대한 많은 종류의 폰켓몬을 포함해서 N/2마리를 선택하려 합니다. N마리 폰켓몬의 종류 번호가 담긴 배열 nums가 매개변수로 주어질 때, N/2마리의 폰켓몬을 선택하는 방법 중, 가장 많은 종류의 폰켓몬을 선택하는 방법을 찾아, 그때의 폰켓몬 종류 번호의 개수를 return 하도록 solution 함수를 완성해주세요.
제한사항
nums는 폰켓몬의 종류 번호가 담긴 1차원 배열입니다.
nums의 길이(N)는 1 이상 10,000 이하의 자연수이며, 항상 짝수로 주어집니다.
폰켓몬의 종류 번호는 1 이상 200,000 이하의 자연수로 나타냅니다.
가장 많은 종류의 폰켓몬을 선택하는 방법이 여러 가지인 경우에도, 선택할 수 있는 폰켓몬 종류 개수의 최댓값 하나만 return 하면 됩니다.
입출력 예
nums result
[3,1,2,3] 2
[3,3,3,2,2,4] 3
[3,3,3,2,2,2] 2
입출력 예 설명
입출력 예 #1
문제의 예시와 같습니다.
입출력 예 #2
6마리의 폰켓몬이 있으므로, 3마리의 폰켓몬을 골라야 합니다.
가장 많은 종류의 폰켓몬을 고르기 위해서는 3번 폰켓몬 한 마리, 2번 폰켓몬 한 마리, 4번 폰켓몬 한 마리를 고르면 되며, 따라서 3을 return 합니다.
입출력 예 #3
6마리의 폰켓몬이 있으므로, 3마리의 폰켓몬을 골라야 합니다.
가장 많은 종류의 폰켓몬을 고르기 위해서는 3번 폰켓몬 한 마리와 2번 폰켓몬 두 마리를 고르거나, 혹은 3번 폰켓몬 두 마리와 2번 폰켓몬 한 마리를 고르면 됩니다. 따라서 최대 고를 수 있는 폰켓몬 종류의 수는 2입니다.
-아름이의 기특한 풀이
- 오늘의 요약 (수업이 끝나고 읽으면 술술 읽힐것들 ! )
지난 시간 로그인에 이어서 오늘은 어떻게 하면 로그인을 유지시켜 줄 수 있을지와 권한분기를 알아봤죠!
오늘 내용 조금 어려우셨나요!? 그래도 복습을 통해 숙지하셔야합니다!
물론 오늘의 로그인 관련 내용은 임시로 적용시켜 줄 수 있는 내용입니다!
지금까지 배운 로그인 프로세스로는 브라우저를 새로고침하거나 페이지를 이동했을 경우 유지가 안됐었죠? 이는 우리가 accessToken을 Browser에 저장시켰기 때문에 화면이 새로 그려지며 초기화 되었기 떄문입니다.
이를 해결하기위해 우리는 브라우저 저장소를 사용할 수 있었죠? 브라우저 저장소에는 3가지가 있었습니다.
Cookie, localStorage, sessionStorage 기억나시나요? 그 중 보안상 문제가 좋지 않지만 원활한 개발을 위해 임시로 localStorage에 저장시켰습니다. localStorage.setItem(“key”,value)과 .getItem(“key”,value)을 활용해 손쉽게 넣어주고 불러줄 수 있었죠?! localStorage는 새로고침 이후에도 사라지지 않는다는 특징이 있었습니다! 즉, 우리가 새로고침한 이후에도 localStorage에 저장 시켜 놓은 accessToken을 setAccessToken을 사용해 집어 넣어주면 만료시간까지 유지가 되겠죠?
여기서 Next.js의 렌더링과 관련된 중요한 포인트가 있었습니다.
Browser에서 요청이 오면 frontend서버에서 미려 그려본 후(Pre-rendering) Browser에 그려준 뒤, 비교(diffing)하고 변경사항을 적용(hydration)해준다고 했습니다. 따라서 frontend 서버에서 그려줄때는 Browser저장소인 localStorage가 없었죠? 따라서 우리는 process.browser 조건이나 typeof window !== ‘undefined’을 주어 실행되는 곳이 Browser일 경우에만 localStorage에 접근하도록 했습니다!
또한 useEffect를 활용하여 화면을 한번 그려준 후 실행시켜주어 해결 할 수도 있었는데, 위 의 3가지 조건 중 우리는 가장 안정적 방식인 useEffect를 사용해주었습니다!
권한 분기의 큰 그림으로는 프론트엔드가 최소 2개 이상으로 분리되었죠!
사용자들이 접속하는 사용자 프론트엔드 서버, 뒤에서 관리자들이 접속하는 관리자 프론트엔드 서버, 더 많게는 판매자용, 구매자용, 중개자용 등등 여러 관리자서버가 존재합니다.
우리는 단지 사용자이기 때문에 매일 사용하는 네이버 홈페이지가 하나밖에 없는줄 알고 있었죠! 하지만 우리가 여태 몰랐던 네이버 관리자 프론트엔드 서버가 존재합니다. 여기에는 네이버 가입자 명단 등등을 게시판 형태로 볼 수 있도록 페이지네이션이 되어있겠죠!
이런 큰 그림의 권한 분기도 있지만, 오늘 배웠던 부분은 사용자 서버 안에서의 로그인한 유저 / 로그인안한 유저를 구분하는 권한 분기였어요!
이 방법으로는 useEffect에서 accessToken이 없으면 /login 화면으로 페이지를 이동시켜 줬습니다.
하지만, 문제가 있었죠! 로그인 권한이 필요한 모든 페이지에 위 로직을 입력해 주어야 한다는 것이었어요!
그래서 우리가 사용한 것이 HOC(Higher Order Component) 였습니다!
HOC(HighOrderComponent)를 알아보기 위해 HOF(HighOrderFunction)도 알아봤죠! 이 개념을 위해 우리는 클로저(closure)의 개념에 대해 배웠는데 그 안에서 우리는 스택구조 대해서 먼저 알아봤어요, 스택구조는 FIrst-in/Last-out(Last-in/First-out) 구조로 즉, 먼저 실행되는 순서대로 쌓이는 구조였습니다! 이 안에서 스코프(범위)의 개념도 알게됬습니다. 스코프 체인! Local->Closure(가장 가까운 외부 함수)->Global 순으로 찾아 간다고 했습니다! 다시말해, 클로저는 외부 함수에 접근할 수 있는 내부 함수를 말합니다!
HOC와 HOF는 Componenet와 Function의 차이였죠!
다시말해, JSX(React의 HTML)를 return 하면 Component, 그렇지 않으면 Function 이었습니다.
HOF 사용 장점은, 기존처럼 event.target.id 라고 직접 입력하지 않아 코드가 짧아진다는 점이었어요!
기존에 material-ui, ant-design 등의 컴포넌트를 이용하면 id값이 날라가는 현상이 있었죠!
또한, id는 전체 태그에서 고유해야하기 때문에, id가 남용되면 대규모 서비스에서 예기치 못한 상황이 발생할 수 있었습니다.
HOF를 사용하면 이러한 점들을 사전에 방지해 줄 수 있고, 사용이 더욱 쉬었어요!
HOC란 특정 컴포넌트를 실행하기 전에 상위 컴포넌트를 먼저 실행시켜 주는 것이었죠!
이렇게 되면 HOC를 하나 만들어 놓고, 로그인이 필요한 컴포넌트 앞에 HOC만 붙여주면 간단하게 권한처리가 끝났습니다!
또한, HOC는 다른 컴포넌트와 함께 실행되므로 with라는 이름을 앞에 붙여줬습니다.
withAuth, withApollo 등이 그 예입니다.
이렇게 우리를 편하게 해주는 HOC와 HOF !!
이게 가능했던 이유는 Javascript의 클로저 덕분이었습니다!
- localStorage
- 우리 어제 로그인해서 받은 토큰으로 들어가서 내 이름 불러올수 있었던 페이지,
새로고침하면 토큰을 못받아와서 튕겨나가는거 설정했었지!- 근데 그러면 안되지 원래는! 로그인 한번하면
계속 내 아이디로 볼 수 있어야하지!
그니까 브라우저 자체에 저장하는 로컬스토리지라는 데에서
새로고침해도 토큰을 받아올수 있는것 알아볼거야 !
- 지금 내가있는 페이지의 개발자도구의 애플리케이션이다!
들어가보면 로컬스토리지에 값이 들어있는것을 확인가능하다 ! 콘솔로 확인가능하다!
그러면 vscode에서도 사용 가능한거겠지?
- 그러면 여기에 토큰을 저장해놓고
브라우저를 껐다가 키더라도 로그인이 유지되게 할 수 있겠지 !!
로컬 스토리지란? 브라우저에 영구적으로 저장되는 값! - 키와 벨류형태로 저장한다
(보안에 취약해서 중요한 정보 안됨,
그래서refresh토큰에 원래 access토큰 담는데
우리는 일단 여기다 담아서 써보자 ! )
쿠키 - 만료시간 설정가능
쿠키는 클라이언트(브라우저) 로컬에 저장되는 키와 값이 들어있는 작은 데이터 파일.
사용자 인증이 유효한 시간을 명시할 수 있으며, 유효 시간이 정해지면 브라우저가 종료되어도 인증이 유지됨.
세션 스토리지 - 브라우저를 끄면 사라진다
세션은 쿠키를 기반하고 있지만, 사용자 정보 파일을 브라우저에 저장하는 쿠키와 달리 세션은 서버 측에서 관리
서버에서는 클라이언트를 구분하기 위해 세션 ID를 부여하며 웹 브라우저가 서버에 접속해서 브라우저를 종료할 때까지 인증상태를 유지
- 로컬 스토리지 언제쓰는건데 ? -한번 로그인해서 여러페이지를 들어갈때 계속 로그인된 내 정보를 불러와야겠지! (시간만료전까진) -비회원으로 장바구니를 담는다 (로컬 스토리지 안에 item : name...등등 이런식으로 저장해놓음)
- vscode로 로컬스토리지에 저장하는 법을 알아두자 브라우저에서 새로고침을 하면 기존에 있던 값에서 html css java...state let.. 변수를 다시 받아오다보니까 안에가 비어있게 되는것 (새로고침하면 초기화가된다) , 다시 로그인해야하니까...
- accessToken을 globalstate에 저장도 했지만, 입력해서 받아오는거였지 결국! **지금은 입력을 한번만 하고 여러번 받아와서 쓰고 싶은거니까** 브라우저의 localstorage 저장해보자 기능별로 로컬스토리지 기능 사용가능 ! ![](https://velog.velcdn.com/images/kimareum/post/dbe97558-43d6-469b-8b9a-ce821fa56f42/image.png) setItem으로 키와 벨류를 저장하는 과정 ! (키와 벨류를 입력하라고 뜬다 ! ) ![](https://velog.velcdn.com/images/kimareum/post/cc7962f5-5272-4fc4-bd0c-fc9fc61ce673/image.png) **localStorage.setItem("accessToken",accessToken)** 요렇게 한줄 적어주고나니 로그인성공 페이지 갔을때 저장이 된것을 확인가능 ! (다시한번 말하지만 accessToken원래 여기에 저장하는것은 안된다! 보안상 ! ) ![](https://velog.velcdn.com/images/kimareum/post/890a5d50-e748-4148-83aa-61c4e7a44530/image.png) 토큰은 잘 저장해줬는데, 새로고침하면 토큰으로 패치를 하진 못한다 ! 새로고침해서 받아올거라고 설정해줘야겠지 ? 새로고침했을때, 로컬스토리지에 있는 accessToken을 가져와라! 라고** app.tsx에 설정을 해줘야한다 ! **
- 원래 recoilstate로 담아놨던 accessToken 화면 ![](https://velog.velcdn.com/images/kimareum/post/2362cd04-ef98-4c11-ab38-a052510affc6/image.png) - set 추가해서 변수로 담아온 부분 ![](https://velog.velcdn.com/images/kimareum/post/e98c796e-8eac-4101-a35a-ffb823184289/image.png) 여기까지하고 실행해보면 localStorage is not defined error가 뜬다 왜? ->next.js렌더링을 이해하러 가보자 ㅋ
- Next.js 렌더링의 Diffing / Hydration
프론트엔드 서버에서 브라우저에 넘기기전에 한번 렌더링을 쫙 해보는것
-> prerendering (프리렌더링)
-모든걸 완벽하게 그리는건 아니고, 유즈이팩트, 컴포넌트디드마운트 같은거 말고,
최초1회만 (마운트되기전까지) 딱 그려봐보는 과정이다
-온체인지, 온클릭 같은거 바인딩 안된상태로, 큰 그림 (div..)만 그려보는것
-그 다음에 브라우저에 넘겨준다
-브라우저에서도 실제로 제대로 그림 그리기전에 한번 그려서
프리렌더링과 비교를 해본다 - (diffing 디핑!)
-비교를해서 디핑(diffing)이후에 최종완성형으로 업데이트해주는 과정을 (hydration)이라한다
-하이드레이션 과정에서 자바스크립트의 기능들 함수들이 다 연결되어 최종적으로 그려진다
- 그래서 프리렌더링 할때는 !
로컬스토리지, 세션스토리지안에 아무것도 없다 (중요!)로컬호스트나, 브라우저라는 개념이 없기 때문이다!
그래서 localstorage is not defined가 나오게 되어버린것 !
1번에는 로컬스토리지가 없고, 2번스토리지에 있어서 에러가 난것이다 !
윈도우는 브라우저를 말해
그래서 콘솔에 window.alert하면 뜨는거 확인가능
window가 있다는 뜻? 브라우저가 있다는뜻 !
if(typeof window === "undefined") 이 말은 프론트엔드 서버라는 뜻이다 !
(브라우저에서 그리는게 아니고, 프론트엔드서버다)
if(typeof window !== "undefined") 이건 브라우져라면,
우리의 오류는 .....
프리렌더링페이지에서는 로컬스토리지가 뭐냐? 못찾겠다! 하는거다그러면 디핑할때 브라우저의 로컬스토리지에 저장된 토큰을
프론트서버의 state값으로 넘겨서
최종 완성형으로 그려줄때 데이터를 받아오면 되겠다 !
그러면 로그인 성공 페이지에 가서 이렇게 써주자,
이렇게 지금은 두가지 방법을 쓸수있다 !
새로고침해도 로컬스토리지에있는 스테이트를 꺼내와서 recoilstate에 넣어주기때문에 가능하다
- 권한분기의 이해
-한사이트의 관리자 페이지이란,
유저목록페이지, 통계기록페이지, 등등 사용위한 사이트가 아닌, 관리를 하기위한 사이트 !
프론트엔드 페이지(도메인이) 3개가 될수도 있고, 하나의 도메인으로 3개를 조건에 나눠쓸수도 있다
같은데이터를 쓰려하는거니 백엔드는 공유하게 되는것 !
하나의 사이트에서, 로그인별로 로그인한사람, 안한사람, 관리자인사람 !을 권한분기를 나누려고 할거다
그러려면 알아야하는 기능중에 하나 !
- 자바스크립트에 이런것이 ? - Closure
함수안의 함수를 실행하는 방법,
return해서 함수를 반환하거나 안에서 안을 실행해야됨
aaa()를 실행할때 return 해주면 함수가 나오는게 보이지
안에있는 값을 나오게 하려면 함수를 실행하고 또 실행해야하기때문에
(aaa( ) ) 얘가bbb가 되는거고 ( aaa ( ) )( )이게 bbb( )이게 되는거다 근데 전체는 안감싸줘도 되어서
aaa( )( )이렇게 적어도 된다 !
그래서 리턴되는 함수의 이름은 필요가 없어 !
aaa( )어차피 이거하면나오고( )걔를 이거붙여서 실행시켜줄꺼니까!
여기서 우리가 알수 있는건, apple은 없지만 스코프체인에 의해서 바깥에 있는 변수에 접근가능해서
가져다가 쓰는것내부함수에서 외부함수의 변수(지역변수)를 closure라고 한다 !
-> 말이 조금 어려운데, 지금 내 지역 바깥쪽의 공간! 이라고 이해하장
안에서 선언을 하는 방법 말고, 함수안에 넣어줘서 결과를 도출하는법 ! (알고리즘 풀때랑 똑같다)
aaa("이건사과에여")("이건바나나에요") => 이게 우리에게 hoc의 개념으로 들어올거야
브라우저에서 그려주다가 여기서 멈추라고 하는 breakpoint(중단점)클릭하면 거기까지만 그려진다 !
스택(stact)과 큐(queue)의 개념이 여기서도 다시 등장하게 되고 !
스택과 큐의 개념 오랜만에 다시보기 !스택(stact) - first in last out/ last in first out -리포구조
큐(queue)- first in first out - 피포구조
예) 쉽게말해 ctrl-z의 기능은, 스택으로 쌓여있어서 누를때마다 가장 최근의 작업 되돌리기 기능이 가능한것!
검사의 callstack부분을 보게되면
스택에 먼저 실행된 aaa함수가 시작되면서 쌓이고,
bbb가 먼저 종료가 되어야 aaa가 종료가 되고 다시 어나니머스로 돌아가야 함수가 끝나는거다
aaa만 실행을 해봤는데, scope에 qqq랑 apple이 undefined로 있네?
호이스팅이 되어서 먼저 변수가 선언만 된거고, 할당은 아직 안된거 !
내부함수의 외부함수의 지역변수들의 공간이 closure인거고
그 안에 apple=10이 있고 그래서 bbb안에서 apple을 사용할수 있는것이다
aaa함수로 돌아가는 순간 closure는 빠지게 된다 (안쪽 공간에서 나왔으니까!)
- React에서 제공하는 hoc와 그를 더 쉽게 사용할수 있게 해주는 hof가 있다
hoc를 custom-hooks로 바꾸는 과정까지...!
- 밑에 로그인 성공페이지에서 토큰을 가져와서 없을때 내보내기 해줬는데,
그러면 로그인이 필요한 모든페이지에 저 부분을 적어줘야한다
게다가 수정하기 부분에서 메시지가 바뀌거나 어떤 값이 바뀌면 모든페이지 들어가서 바꿔줘야한다
useEffect 부분을 빼놓고, import해서 페이지 그리기전에 검증하는 컴포넌트로 쓰면 어떨까?
그게 바로 Higher Order Component !!!!!!
- HOC / HOF
HOC - Higher Order Component ( 접속 전에 먼저 실행되는 컴포넌트)
간단하게 개념부터 이해해보자
Aaa가 부모고 Bbb가 자식인거고 이름은 철수입니다로 나오게 되겠지
이것을 가지고 함수형 컴포넌트를 그냥 함수로 변경하는것도 했었지
이게 우리가 생각해야할 부분이고, closure를 사용해줄꺼다
함수안에서 함수를 리턴하고 있기 때문에
중간 로직함수를 하나더 넣을수 있겠지!
먼저실행 컴포넌트 부분을 hoc라고 부른다 !
(사이트를 열기전에 검증이 필요하거나, 데이터를 불러와야 할때 자주 쓰일거야 !)
간단하게 이해하는 과정
중간에 <Component {...props}/>
이게 Bbb( {qqq:"철수"} )
정리부분
보통 검증하는 부분의 이름은 with가 붙게된다 (with보면 HOC인가? 생각하기!!관례니까!)
HOC가 컴포넌트라고 했다면 우리가 이렇게 썼다면
HOF는 하이오더펑션!
jsx를 리턴하지 않는다
onclickchild실행 el실행 event실행
클로저덕에 (el) (event)를 빨간박스 안에서 다 쓸 수 있다.
원래는 태그안에 id를 줘서 event.target.id를 썼었는데
el로 넘겨서 쓰는거고 event도 쓸수있게 되는거다
꼭 두개가 아니라 순서에 맞게 값을 계속 넣어줄수가 있다
map함수안의 el값을 받아서 다시 그 함수에 넣어줘서 결과가 찍힌다는게 hof!
- 오늘의 알고리즘 풀이
오늘은 알고리즘 시험이 있는날이었는데 마지막 문제를 못풀어따 근데 다른사람들은 후딱풀고 코드 알려주고 배우다보니까 나는 왜 이런생각을 못했을까 또또! 자책하고 그랬는데...! 이거 엄청 안좋은 습관같다!
- 내가 나에게 실망한 포인트는
-문제를 보고 어떠한 방법과 메서드로 접근해야할지 다양한 방법이 떠오르지 않아서 (경험과 견문이 좁아)기본 if와 for문으로 해결하려 복잡하게 생각했다는것
-테스트케이스를 열어서 주어지는 변수들을 정확히 확인안하고 생각속에서만 확인하고 undefined만 보다가 포기한 점
-그 기분을 이어받아 알고리즘 시간에 집중하지 않고 나중에 들어야지하고 집중하지 않은것 자책한것 집에 빨리갈래라고 생각할것
- 이 느낀점을 토대로 나의 발전을 위해 해야할 행동
-경험이 부족하고 투자한 시간이 부족하다는것을 알았으니 알고리즘 공부 매일 1시간반 이상씩 할 것
-어려운 풀이가 나왔어도 이해하고 내것으로 만드려고 노력할것
-자기반성과 비하에 오랫동안 빠져있지말고 자기발전의 토대로 삼을것
Author And Source
이 문제에 관하여(23일) 브라우저에도 저장공간이 있대!.. localStorage/Next.js 렌더링의 Diffing / Hydration/권한분기/Closure/HOC / HOF code camp fe 6기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@kimareum/Code-camp05-03저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)