새로고침시 state가 사라지게된다.(비워져 초기 상태로 돌아감ㅁ-> html,css,js등을 다시그리게되기때문)(즉, state도 변수나 마찬가지인데, 새로고침하면 새로운 html을 받아와 그리기에 기존것이 날라가는것.
따라서 다시 만들어야하는데(refreshToken), 그 전까지는 임시로로컬 스토리지에 저장해보자.

(이 방법은 실무에서 사용하기에는 좋지 않다. 보안문제가 발생할 수 있는데, 이후에 수업이 진행될것이다.)


localStorage에 accessToken담기.
세션 -> 껐다키면 사라지게에 일단 로컬에....

+ nextjs 원리.


localStorage.setItem으로 로컬스토리지에 저장함.
그러나 저장만 한것이니 새로고침시에는 사라짐.
따라서 이것을 다시 recoil에 저장!!
저장한것을 다시 Athorization에 넣고 보내기

localStorage.getItem으로 꺼내오기

_app.tsx에 가서

const result = localStorage.getItem("accessToken");
  console.log(result);
  setAccessToken(result ?? "");

이렇게 로컬스토리지에 저장된것을 꺼내 다시 recoil에(글로벌 state에)담는다.
그런데!

라는 오류가뜬다.

그런데 함수안에 넣고...=> 버튼을 클릭햇을때 console.log가 찍히게하면 문제 없이 찍힌다.


Next.js의 작동원리

프론트 서버를 yarn dev로 키고, 브라우저에서 주소를 치면 이 서버에 접속하여 html,css,js를 받아오고, 이후 브라우저에서는 벡엔드에 쿼리, 뮤테이션을 날리고, 벡엔드는 api요청을 보낸것을 받아오는것인데...

이때 브라우저에서는 html을 먼저 받아온다.
(우리가 작성하는 코드들은 자체적으로 html로 바뀌어 실행되게됨(자동으로 next나 react가 만들어줌))
그다음 이 html을 실행하며 script태그를 만나게되면 다시 서버로 가서 다운받아오고,css, js도 받아온다.(css 가 없다면 emotion에서 inline형태로(태그안에 style적는 방식)바꿔주게된다.)

이 과정에서...


nextjs는 서버에서 해당 html코드를 미리한번그려본다. => 프리랜더링이라고함.

미리= 프리
이렇게 프리랜더링을 통해 html코드를 만들어주게되고, 이 코드를 브라우저로 전달해준다.

브라우저는 그것을 다운받아와 그리는데, (미리그려놓은것을화면에 먼저 그림 ->> 빠르게 그림만이라도 먼저 보여줌.)
이후에 js를 요청하고 받아온다.
그다음 이 js의 내용을 가지고 서버에서 받은내용과 다른지 보고, js를 통해 html을 다시그리며 js의 기능들을(onClick등) 적용시킨다.(js를 통해 html업데이트)

==> 이 과정에서 차이점을 비교한다.
1. 일단 껍데기를 먼저보여준다
2. js를 다운로드 받아오며 차이점이 있는지 비교하면서 기존의 껍데기(html)을 업데이트한다,
기능을 적용한다.(비교하면서 효율적으로 그리게된다)

=> 아무것도 없던 껍데기를 업데이트 하는것을 디핑 Diffing, 여기에 js등을 적용하는것을 하이드레이션 hydration이라고한다(수화작용-> 메마른 대지에 물을 줌)

---> 그럼 왜 위에 사진에 나온 오류가 나온것일까?

yarn dev에서 프리렌더링시 localStorage가 없기때문에 생긴에러이다.
window의 기능이기에 서버에서 막힌것이다.
(함수안에 넣었을때 가능한경우는 프리랜더링시에는 그냥 화면 그리기만 하기때문이다.)
alert또한 마찬가지이다.

어떻게 해결할까??

    1. 조건문으로 브라우저일때만 사용
    1. useEffect => html을 받아 화면이 다 그려진 후 실행되는것.

이렇게 두가지 방법이 있다.

여기서 조건문에서는 또 두가지로 나뉜다.

process.browser방법,
typeof window방법

  1. process.browser방법
     if (process.browser) {
        alert("방가 . 지금은 브라우저~");
        console.log("지금은 브라우저");
        const result = localStorage.getItem("accessToken");
        console.log(result);
        setAccessToken(result ?? ""); // result가 없으면 어쩔껀데? 없으면 빈문자열로!!
        // => 일단 로컬스토리지에 저장되는것은 객체여도 문자열로 저장됨
        // 일단 accessToken을 로그인시 받으면 그것을 활용하고 로컬스토리지에 저장함,
        // 새로고침시 사라지는데 이때는 로컬스토리지의것을 꺼내 accessToken에 담고 그것을 다시 보내주어 받은 토큰이 사라지지않게함
      } else {
        console.log("지금은 프론트엔드 서버다!!");
      }

2.typeof window방법
>```
 if(typeof window !=="undefined"){
    console.log("지금은 브라우저");
  }else{
    console.log("지금은 프론트엔드 서버다!!");// 즉 yarn dev로 실행한 부분
  }
  1. useEffect를 사용해 프리랜더링시에는 전혀 연관없게(프리랜더링 무시하기)
    --> 가장깔끔한 방법이라 지금 적용할 방법이다.
  useEffect(() => {
    // console.log("지금은 브라우저");
    const result = localStorage.getItem("accessToken");
    setAccessToken(result ?? "");
  }, []);

useEffect의 경우 앞에서도 언급했듯 화면이 다 그려지고, 실행되기에 프리랜더링과는 연관이 없다.


로그인 권한검증

  1. useEffect로 해보기
    accessToken이 필요한 페이지 실행시 없다면 로그인페이지로 이동하기
     useEffect(() => {
        if (localStorage.getItem("accessToken") === null) {
          // accessToken이 없으면..
          // 없으면 null임.
          alert("로그인 후 이용 가능합니다");
          void router.push(`/section23/23-03-login-check`);
        }
      }, []);

더 효율적인 방법:


closure 실습

stack => 먼저들어온게 마지막에 빠진다.(차례대로 쌓이다가 마지막게 먼저빠지게됨(실행됨)) ==> LIFO구조.(Last In First Out)

que => 먼저 들어온게 먼저나간다 => FIFO구조 => 후반에 이벤트 루프부분에서 다루어짐.

지금 scope에 Local이라고 되어있다 ==>

지금 현재 내가있는 영역 안에서라는 의미.
옆쪽에보면 call stack이라는 부분이 보인다. 실행된 순서대로 쌓이게되며 나중에쌓인것이 먼저 사라진다.

Closure스코프. => 내가 있는곳(Local)에 없으면 그 위로 올라가 찾는것. 이 클로져에도 없다면 Global로 올라감

==> 이것이 스코프 체인!!

호이스팅?
미리 js에서 무엇이있는지 읽어보아 뭐가있는지 알고있는것이라고 할 수 있음.

다만, let, const는 선언만되었다고 인식만하지 실제로 선언되고 값이 할당되지 않아 접근이 불가한 반면(TDZ에 들어가있다) var은 접근이 가능해 문제가 될 수 있다

정확하게 호이스팅이라는것은... => 해당 실행 컨텍스트에서 존재(선언되는)하는 변수와 함수들을 끌어올리는것.


함수 안의 함수(HOF)

(함수 위의 함수)

// 1. 함수를 리턴하는 함수
// aaa를 실행하는순간 결과로 bbb가 나오고, 이 bbb를 실행하려면 aaa함수 옆에 소괄호 하나 더 붙이면 return 하는 bbb에 소괄호 붙이는ㄴ것과 마찬가지
function aaa() {
  const apple = 10;
  return function bbb() {
    const banana = 20;
    console.log(banana);
    console.log(apple);
  };
}
aaa()();
// 어차피 실행하면 내부의 함수 이름은 나오지 않으니 이름 필요없음

// 2. 함수를 리턴하는 함수 -인자를 받아 사용
function aaa1(apple) {
  return function (banana) {
    console.log(banana);
    console.log(apple);
  };
}
//   undefined
aaa1(100)(500);
//    500
//    100

// 3.  화살표함수로 만들기.
const aaa2 =
  (apple) =>
  // { // 중괄호롸 retrun사이에 아무것도 없으니 생략가능

  //     return
  (banana) => {
    console.log(banana);
    console.log(apple);
  };
//   }

//   undefined
aaa2(100)(500);
//    500
//   100

//  ==> 생략한것
const aaa3 = (apple) => (banana) => {
  console.log(banana);
  console.log(apple);
};

aaa3(100)(500);

// 4. 인자가 여러개

const ccc = (tomato) => (apple) => (banana) => (orange) => {
  console.log(banana);
  console.log(apple);
  console.log(tomato);
  console.log(orange);
};
//   undefined
ccc(50)(30)(10)(5);
//    10
//    30
//    50
//    5
const onClickPage = (page: number) => (): void => {
    //   void refetch({ page: Number(event.currentTarget.id) }); // 아래쪽에서 변수에 담거나 하는것이 없으니 async / await로 기다릴 필요는 없기에 void
    void refetch({ page }); // 아래쪽에서 변수에 담거나 하는것이 없으니 async / await로 기다릴 필요는 없기에 void
  };

  return (
    <div>
      {data?.fetchBoards.map((el) => (
        <div key={el._id}>
          <span style={{ margin: "10px" }}>{el.title}</span>
          <span style={{ margin: "10px" }}>{el.writer}</span>
        </div>
      ))}
      {new Array(10).fill(1).map((_, index) => (
        <span
          key={index + 1}
          //   id={String(index + 1)}
          onClick={
            onClickPage(index + 1) // id를 직접 함수로 넣어줌.

            // 원래는 여기에 소괗호 하나 더 있어야하지만 js에서 자동으로 event를 넣어주니 생략
            // event는 뒤쪽에 들어옴!!
          }

          {index + 1}
        </span>

HOC

(상위 컴포넌트)

로그인체크를 분리하고, 마이페이지접속시에 로그인 체크 로직이 먼저 실행되는것.(로그인체크를 하고, 해당 페이지에 접속됨)
로그인 안한 사람도 접근 가능하게하려면 => 로그인체크로 감싼 부분을 빼면됨

export default 로그인체크(마이페이지) ==> export default 마이페이지


HOC => hof와 비슷하나 jsx를 리턴하는것

결국 app.tsx의 Component로 합쳐져 실행되고, 이 부분도 함수로 바꿀수 있으니 => => {Component({qqq:"철수"})}

이 부분이 각각 로그인체크 함수의 인자들로 각 자리에 들어가게되어 ===> 첫부분은 컴포넌트가, 두번째 매개변수에는 props가 들어감!!

권한부분은 page에!! 이름은 withAuth 등... (권한분기)

0개의 댓글