[23-1] 새로고침 이후 재접속 과정
[23-2] 브라우저에 accessToken 저장하기
[23-3] Next.js의 렌더링 방식
[23-4] 권한분기
[23-5] 권한분기를 진행하기 위한 필요한 사전지식
[23-6] 함수를 리턴하는 함수 HOF
[23-7] HOC
🎯 브라우저 저장소에 토큰을 저장하는 방식은 실무에서 사용하는 방식이 아니다. refreshToken을 배우기 전 정확한 방법을 알아가기위한 준비단계
login-localstorage
import { gql, useMutation } from "@apollo/client"; import { useState } from "react"; import type { ChangeEvent } from "react"; import type { IMutation, IMutationLoginUserArgs, } from "../../../src/commons/types/generated/types"; import { useRouter } from "next/router"; import { useRecoilState } from "recoil"; import { accessTokenState } from "../../../src/commons/stores"; const LOGIN_USER = gql` mutation loginUser($email: String!, $password: String!) { loginUser(email: $email, password: $password) { accessToken } } `; export default function LoginPage(): JSX.Element { const router = useRouter(); const [, setAccessToken] = useRecoilState(accessTokenState); const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const [loginUser] = useMutation< Pick<IMutation, "loginUser">, IMutationLoginUserArgs (LOGIN_USER); const onChangeEmail = (event: ChangeEvent<HTMLInputElement>): void => { setEmail(event.currentTarget.value); }; const onChangePassword = (event: ChangeEvent<HTMLInputElement>): void => { setPassword(event.currentTarget.value); }; const onClickLogin = async (): Promise<void> => { try { // 1. 로그인 뮤테이션 날려서 accessToken 받아오기 const result = await loginUser({ variables: { email, password }, }); const accessToken = result.data?.loginUser.accessToken; console.log(accessToken); // 2. 받아온 accessToken을 globalState에 저장하기 if (accessToken === undefined) { alert("로그인에 실패했습니다! 다시 시도해 주세요!"); return; } setAccessToken(accessToken); localStorage.setItem("accessToken", accessToken); // 임시 사용(나중에 지울 예정) // 3. 로그인 성공 페이지로 이동하기 void router.push("/section23/23-02-login-success-localstorage"); } catch (error) { if (error instanceof Error) alert(error.message); } }; return ( <> 이메일: <input type="text" onChange={onChangeEmail} /> 비밀번호: <input type="password" onChange={onChangePassword} /> <button onClick={onClickLogin}>로그인</button> </> ); }
setAccessToken(accessToken); localStorage.setItem("accessToken", accessToken); // 임시 사용(나중에 지울 예정)
로그인
새로고침
💡 diffing 과 hydration
diffing
: 브라우저에서 그린내용과 프론트엔드 서버에서 렌더링한 내용을 얼마나 차이 나는지 비교하게 되는 과정
hydration
: diffing을 통해 비교한 후 최종적으로 반영해 렌더링하게 되는 과정
apollo
import { ApolloClient, ApolloLink, ApolloProvider, InMemoryCache, } from "@apollo/client"; import { createUploadLink } from "apollo-upload-client"; import { useRecoilState } from "recoil"; import { accessTokenState } from "../stores"; import { useEffect } from "react"; const GLOBAL_STATE = new InMemoryCache(); // 컴퓨터 메모리에다가 백엔드에서 받아온 데이터 모두 임시로 저장해놓기 => 나중에 알아보기 interface IApolloSettingProps { children: JSX.Element; } export default function ApolloSetting(props: IApolloSettingProps): JSX.Element { const [accessToken, setAccessToken] = useRecoilState(accessTokenState); // 3. 프리렌더링 무시 - useEffect 방법 useEffect(() => { const result = localStorage.getItem("accessToken"); setAccessToken(result ?? ""); }, []); const uploadLink = createUploadLink({ uri: "백엔드 주소", headers: { Authorization: `Bearer ${accessToken}` }, }); const client = new ApolloClient({ link: ApolloLink.from([uploadLink]), cache: GLOBAL_STATE, // 컴퓨터의 메모리에다가 백엔드에서 받아온 데이터 모두 임시로 저장해놓기 => 나중에 알아보기 }); // prettier-ignore return ( <> <div>안녕하세요 영희입니다</div> <ApolloProvider client={client}> {props.children} </ApolloProvider> <div>안녕하세요 훈이입니다</div> </> ); }
// 3. 프리렌더링 무시 - useEffect 방법 useEffect(() => { const result = localStorage.getItem("accessToken"); setAccessToken(result ?? ""); }, []);
로그인을 한 사람
과 로그인을 하지 않은 사람
.운영자로 로그인
한 사람, 판매자로 로그인
한 사람, 거래처 사장님으로 로그인
한 사람 등 다양하게 권한을 분리할 수 있다.📂 스택과 큐
스택
: 출입구가 하나인 우물 형태의 데이터 구조
큐
: 양방향 출입이 가능한 파이프 형태의 데이터 구조
📂 스코프 체인
<!DOCTYPE html> <html lang="ko"> <head> <title>클로저 실습</title> <script> function aaa(){ banana = 3 console.log(banana) } aaa(); </script> </head> <body> </body> </html>
📂 클로저(closure)
<!DOCTYPE html> <html lang="ko"> <head> <title>클로저 실습</title> <script> function aaa(){ const apple = 10 function bbb(){ console.log(apple) } bbb() } aaa(); </script> </head> <body> 클로저 실습 </body> </html>
💡 스코프 체인과 클로저 정리
클로저(closure)
: 상위 함수 + 상위함수의 lexical enviroment(상위함수를 둘러싼 환경)스코프 체인(scope chain)
: 바로위 함수 스코프 뿐만아니라 global 스코프 까지 찾아 올라가는 과정을 scope chain
📂 호이스팅
// closure.html 파일 <!DOCTYPE html> <html lang="ko"> <head> <title>클로저 실습</title> <script> function aaa(){ const apple = 10 function bbb(){ console.log(apple) } bbb() const qqq = 3 } aaa(); </script> </head> <body> </body> </html>
함수 선언식
function aaa(apple){ return function bbb(banana){ console.log(banana) console.log(apple) } } aaa(2)(3) // 실행 결과 // 2 => aaa에 넣은 인자값 // 3 => bbb에 넣은 인자값
화살표 함수로 변경
const aaa = (apple)=>{ return (banana)=>{ console.log(apple) console.log(banana) } } aaa(2)(3)
최종
const aaa = (apple)=>(banana)=>{ console.log(apple) console.log(banana) } aaa(2)(3)
HOC
: Higher Order Component 개념은 위의 클로저로부터 확장된 개념