오늘의 팁: CRUD 기반 기술을 익히고, 여기서 얼마나 더 재사용성이 높은, 간결한(리팩토링이 된) 백엔드의 개념까지 익히면 front-end에 있어서 좋다 + 오픈 api같은 것을 추가하면 더 좋음

대부분의 회사는 함수형 컴포넌트를 쓰고있지만 옛날에 만들었거나 구성된 서비스들의 경우 클래스형 컴포넌트를 사용중이기 때문에 우리는 서로 변환할 수 있는 능력과 클래스형 컴포넌트가 뭔지 알아야함.

그래서 클래스가 뭐임?

물건 만드는 설명서에 가깝다

이 설명서 안에 함수들을 넣을 수 있음, 이 함수들을 메소드라고함

몬스터를 생성하고 공격이나 도망치게 할 수도 있음..!

컴포넌트를 넣을 수도 있다.
게시판의 쓰기버튼, 확인버튼도 다 여기 안에 들어감

date 도
date.getFullYear()
date.getMonth()
date.getDate()
를 사용할 수 있음
이러면 FullYear면 년도추출, Month명 월 추출 기능, Date면 일 추출인것을 알 수 있다.

여기서 Date는 우리가 만든게 아니고 자바스크립트의 내장 객체,
date는 객체, 객체지향 프로그래밍-OOP 라고 할 수 있다.

그래서 객체지향이 뭐죠??

카운터 컴포넌트 실습
!react에서 Component를 가져와야한다.
setState는 어디갔냐면 extends Component안에 있음
그리는 부분은 render(){} 안 return()부분에 넣어야함
함수를 만들때는 function 을 안쓰고 이름만 지정해줘도 됨.
클래스 안에 있는 것들에 접근할 때는
this. state, this.onClickCounter처럼 this를이용해서 접근해야함

import { Component } from "react";

export default class MyCounterPage extends Component {
  state = {
    count: 0,
  };

  onClickCounter() {
    console.log(this.state.count);
  }

  render() {
    return (
      <>
        <div>현재 카운트 :{this.state.count}</div>
        <button onClick={this.onClickCounter}>카운트 올리기!!</button>
      </>
    );
  }
}


근데 누르면

state 가 정의되지 않음(undefined)라고 뜬다.

this가 클래스나 다른곳에 포함되지 않으면 window에 포함된다.

개발자도구에서 그냥 this라고 치면 window가 나옴

여기서 왜 그런지 알 수 있다.
코드에서 console.log(this.state.count)가 언제 실행되느냐 :
onClickCounter의 onClick이 눌리고 나서 실행됨 - >
그렇게 되면 onCluckCounter의 this는 새로운 환경에서 실행되기 때문에 class랑은 상관이 없게됨 ->
그럼 여기의 this는 state의 this를 가리키는 것 같고 우리가 원하는 것이지만 실제로는 window를 가리키게 됨
그렇다면 이걸 고치려면 this가 어디의 this인지 알려줘야함

<button onClick={this.onClickCounter.bind(this)}>카운트 올리기!!</button>

.bind(this)를 추가한다. 그래야 class 안의 this라는 것을 알아들을 수 있음

이후 자바스크립트가 나오면서 화살표함수가 나오게 됨 그래서 이런 문제가 해결됨

import { Component } from "react";

export default class MyCounterPage extends Component {
  state = {
    count: 0,
  };

  onClickCounter = () => {
    console.log(this.state.count);
  };

  render() {
    return (
      <>
        <div>현재 카운트 :{this.state.count}</div>
        <button onClick={this.onClickCounter}>카운트 올리기!!</button>
      </>
    );
  }
}

Lexical(언어적)인 this가 맞게 되서 bind를 써지 않아도 된다고 한다.
Lextical scope란 함수를 어디서 호출하는지가 아니라 어디에 선언하였는지에 따라 결정된다는 개념이다.

이제 그럼 카운트가 작동되게 만들어보자.+타입스크립트, I를추가해서 선언한다음 interface 를 통해서 타입을 지정해준다.
그리고 나서 신경쓰이면 src/components/units/에 넣어주면된다.

import { Component } from "react";

interface IState {
  count: number;
}
export default class MyCounterPage extends Component {
  state: IState = {
    count: 0,
  };

  onClickCounter = () => {
    // console.log(this.state.count);
    this.setState((prev: IState) => ({
      count: prev.count + 1,
    }));
  };

  render() {
    return (
      <>
        <div>현재 카운트 :{this.state.count}</div>
        <button onClick={this.onClickCounter}>카운트 올리기!!</button>
      </>
    );
  }
}

컴포넌트 생명주기

컴포넌트들의 이름은 단순, 직관적인 편임
원래 훨씬 많았으나 deprecated, 더 이상 지원하지 않는 기능들이 많이 생김 함수이름들에 함수이름 이렇게 표시된 것들이 대표적인 더 이상 지원하지 않는 함수들

이런 것들이 더 이상 지원하지 않는 것들이다.

그럼 이런건 언제 사용하는건가요?

이런 입력창의 커서가 깜빡이는 것 또한 그냥 그려지는게 아니다

인풋창(입력창)을 먼저 그리고(render)난 뒤에 커서가 깜빡이는 것을 보여주는 것(componentDidMount)

WillUnmount 같은경우는 백엔드 서버에 연결이 끊겼다고 메세지를 보낼 때 사용함

import { Component } from "react";
import MyComponent from "../../src/components/units/classcomponent";
import Router from "next/router";

interface IState {
  count: number;
}

export default class MylifeCycle extends Component {
  state: IState = {
    count: 0,
  };

  componentDidMount() {
    console.log("마운트됨!!");
  }

  componentDidUpdate() {
    console.log("수정됨!!");
  }

  componentWillUnmount() {
    console.log("잘가요~");
  }

  onClickCounter = () => {
    // console.log(this.state.count);
    this.setState((prev: IState) => ({
      count: prev.count + 1,
    }));
  };

  onClickMove = () => {
    Router.push("/");
  };

  render() {
    return (
      <>
        <div>현재 카운트 :{this.state.count}</div>
        <button onClick={this.onClickCounter}>카운트 올리기!!</button>
        <button onClick={this.onClickMove}>페이지 이동하기</button>
        <MyComponent count={this.state.count} />
      </>
    );
  }
}

ref

mount됨이라고 해봤자 실제로는 뭔지 모르니까 한번 써보기!!
ref는 reference 참조한다의 약자이다.(페이지를 이동시키는 href와는 다르다)
태그들을 참조할 수 있다. 태그들을 변수에 담아서 쓸 수 있다는 뜻이다. 한번 담아보겠습니다.

함수이름 = creatRe인 변수를 만들고 (자동으로 react에서 import 해옴)
render쪽에 input 창을 만들고 inputRef를 연결한다.
componentDidMount부분에 this.inputRef.current?.focus(); 를 추가한다


그러면 인풋창을 찾아서 커서를 깜빡이게하는(focus) 기능을 구현할 수 있다.

import { Component, createRef } from "react";
import MyComponent from "../../src/components/units/classcomponent";
import Router from "next/router";

interface IState {
  count: number;
}

export default class MylifeCycle extends Component {
  inputRef = createRef<HTMLInputElement>();
  state: IState = {
    count: 0,
  };

  componentDidMount() {
    console.log("마운트됨!!");
    this.inputRef.current?.focus();
  }

  componentDidUpdate() {
    console.log("수정됨!!");
  }

  componentWillUnmount() {
    console.log("잘가요~");
  }

  onClickCounter = () => {
    // console.log(this.state.count);
    this.setState((prev: IState) => ({
      count: prev.count + 1,
    }));
  };

  onClickMove = () => {
    Router.push("/");
  };

  render() {
    return (
      <>
        <input type="text" ref={this.inputRef} />
        <div>현재 카운트 :{this.state.count}</div>
        <button onClick={this.onClickCounter}>카운트 올리기!!</button>
        <button onClick={this.onClickMove}>페이지 이동하기</button>
        <MyComponent count={this.state.count} />
      </>
    );
  }
}

이거를 다시 함수형 컴포넌트로 바꾸면..?
!!다시강조하면 옛날에는 다 class형이었기때문에 함수형으로 바꾸거나 class형을 사용하거나 어떻게 사용하는지 어떻게 바꾸는지 알아둬야한다!!

useEffect와 의존성 배열(dependency array)

componentDidMount, componentDidUpdate, componentWillUnmount가 useEffect가 화면 안으로 다 들어가게됨

 useEffect(() => {}, []);

저기서 []부분을 의존성 배열, dependency array라고 부른다. 저 배열에 의존하고 있다. 라는 뜻인데

[]안에 뭐가 들어가냐에 따라서 실행되는 방식이 다름, 만약에 count면 카운트가 올라갈때마다 다시 실행, 없으면 뭐가 하나라도 바뀌면 다시 실행, didUpdate같이 실행하는 느낌이다.

import { useEffect, useRef, useState } from "react";
import { useRouter } from "next/router";

export default function MyLifeCyclePage() {
  const [count, setCount] = useState(0);
  const router = useRouter();
  const inputRef = useRef<HTMLInputElement>(null);

  // componenentDidMount와 동일
  useEffect(() => {
    console.log("마운트됨!!");
    inputRef.current?.focus();

    return () => {
      console.log("잘가요~");
    };
  }, []);
  // componenentDidUpdate와 비슷
  useEffect(() => {
    console.log("수정됨!");
  });

  function onClickCounter() {
    setCount((prev) => prev + 1);
  }

  function onClickMove() {
    router.push("/");
  }

  return (
    <>
      <input type="text" ref={inputRef} />
      <div>현재 카운트 :{count}</div>
      <button onClick={onClickCounter}>카운트 올리기!!</button>
      <button onClick={onClickMove}>페이지 이동하기</button>
    </>
  );
}

useEffect 주의사항

useEffect의 의존성 배열을 좀 더 보자

import { useState, useEffect } from "react";

export default function UseEffectDependencyArrayPage() {
  console.log("랜더링시작!!");
  const [count, setCount] = useState(0);

  // //1번 케이스 - 최초 1번 실행(DidMount)
  // useEffect(() => {
  //   console.log("최초 1번 실행됨!!");
  // });

  // //2번 케이스 - 의존성 배열의 count 감지 후 재실행
  // useEffect(() => {
  //   console.log("count가 변경되면 재실행!!");
  // }, [count]);

  // // 3번케이스 - 최초렌더링 + 1
  // useEffect(() => {
  //   setCount(100);
  // }, [count]);

  // 4번케이스 - 무한루프
  // useEffect(() => {
  //   setCount((prev) => prev + 1);
  // }, [count]);

  function onClickCounter() {
    setCount((prev) => prev + 1);
  }

  return (
    <>
      <div>현재 카운트 :{count}</div>
      <button onClick={onClickCounter}>카운트 올리기!!</button>
    </>
  );
}
  1. reder가 되고 한번만 실행됨

  2. 버튼이 누를때마다 재실행 = 의존성 배열의 count 감지 후 재실행

  3. 한번만 실행되는데 setCount로 한번 더 나옴 = 최초렌더링 + 1
    (그래서 두번)

  4. 시작하자마자 1을 더하기
    0으로 useState가 있었는데 setCount에서 더하고 그리고 , 다시 더하고 그리고 무한히 반복하게됨.! 빨리 끄자

퍼블릭 API 사용해보기, 이미지 업로드
https://github.com/public-apis/public-apis


이렇게 종류가 엄청 많다

git에 다양한 API를 사용할 수 있다
이건 모음집일 뿐 사용법을 많이 익혀보는 게 좋다


랜덤 강아지를 postman으로 가져오는 테스트의 모습

이걸 vs코드에 넣어보자

import axios from "axios";
import { useEffect, useState } from "react";

export default function OpenapiWithUseEffectPage() {
  const [dogUrl, setDogUrl] = useState("");

  useEffect(() => {
    async function fectchDog() {
      const result: any = await axios.get(
        "https://dog.ceo/api/breeds/image/random"
      );
      setDogUrl(result.data.message);
    }
    fectchDog();
  });

  return (
    <>
      <div>오픈API 연습!!</div>;
      <img src={dogUrl} />
    </>
  );
}

요약
클래스 사용에서는 this가 문제였음, 사용되면서 this가 참조하는 위치가 윈도우로 나가버렸기 때문에 onclick 속성에 bind를썼어야함(ex :.bind(this)), 아니면 화살표 함수를 통해서 언어적으로 보는 this를 맞게, 렉시컬(lexical)this라고 한다.
컴포넌트의 생명주기를 class 컴포넌트에서는 componentDidMount(ref를 활용해서 인풋 태그에 focus()맞추기, componentDidUpdate
componentWillUnmount(백엔드로 활성화 비활성화 신호 보내기) 등등으로 확인해봤고

이를 함수형으로 바꾸면 useEffect가 나온다. 이때 dependency array(의존성 배열)이 중요해짐
이를 이용해서 조정하기,
useEffect에서 state를 변경시 추가적인 렌더링 발생하는 것 기억하기
useEffect에서 변경한 state가 dependencyt arry에 걸려있을 경으 무한루프가 발생하는 것 알아두기(4번)

그리고 axious 를 활용해서 API를 사용해보기, 만들어보기

profile
개발자 새싹🌱 The only constant is change.

0개의 댓글