16일차 컴포넌트와 생명주기

osdsoonhyun·2023년 2월 27일
0

코드캠프

목록 보기
12/22
post-thumbnail
  1. 클래스 컴포넌트, 클래스는 무엇인가? -> Class-Component
  2. this? 뭔데 이가 말썽이야! -> this
  3. 컴포넌트의 생명주기 -> Component-Lifecycle

포트폴리오 리뷰

inputs 리팩토링

  // const [writer, setWriter] = useState('');
  // const [title, setTitle] = useState('');
  // const [contents, setContents] = useState('');
  const [inputs,setInputs] = useState({
    writer:"",
    title:"",
    contents:""
  })
  • 객체 형태로 묶어서 초기화한다.

  • onChangeWriter에서는 입력 값을 넣어주고 title과 contents의 기존 값을 넣어줘야 한다.
  • onChangeTitle, onChangeContents도 동일한 방법으로 적용한다.
const profile = {
  name: "철수",
  age: 12,
  school: "다람쥐초등학교",
  age: 13

console.log(profile) //{name: "철수", age: 13, school: "다람쥐초등학교"}
  • 위에서 보는 것과 같이 아래에 있는 key가 위에 있는 중복되는 age key를 덮어쓴다.
  • 기존의 값을 쓰고 spread 연산자를 활용하여 입력 받은 값을 덮어씌운다.

  • 겹치는 부분이 많은데, 그 부분들을 통일시켜보자
  • map으로 목록 10개 뿌릴 때 이때 목록을 클릭했을 때 상세보기로 들어가도록 하는 실행되는 함수를 10개 만들지 않고 1개의 함수만 만들고 id 값을 다르게 가지고옴으로써 각각의 상세페이지로 이동할 수 있었다.
  • 이를 활용하여 하나의 함수를 onChangeWriter, onChangeTitle, onChangeContents에도 id 값을 다르게 하여 각기 다른 함수로 만들어보자.
  • 작성자 입력했을때 들어가는 id 값은 writer이다. 따라서 setInputs에 들어가는 변경된 값을 id로 대체해주는데, event.target.id로 할 수 있다. 여기서 문제가 발생한다.
const profile = {
  name: "철수"
}

const profile = {
  event.target.id = "훈이"
}

profile[name] // 철수
profile[event.target.id] // 훈이
  • key 값에 event.target.id가 들어가면 안되고 변수로 봐야한다.
  • 그렇다고 변수가 들어가면 key값에 변수를 넣어줘야하므로 대괄호로 감싸줘야 한다.
  • value 에서 사용하는 대괄호는 배열을 의미하고 key에 대괄호를 사용하면 event.target.id에 들어있는 변수를 key로 사용할 수 있다.

  • variables도 스프레드 연산자로 줄였다.
  • return에서 작성자, 제목, 내용도 map으로 줄일 수 있지만 UI 추가를 위해 남겨두었다.

Class-Component

클래스란?

  • 물건 만드는 설명서

  • 위와 같은 프로그래밍기법을 객체(객체지향프로그래밍-OOP)라고 한다.

class component 만들어보기

  • class는 화면을 보여주는 기능이 없고 리액트가 제공하는 render를 통해 화면에 보여줄 수 있다.

  • render 사용을 위해너느 import {Component} from "react" + extends Component해주어야 한다.

  • 다중 상속 X

  • extends Component 를 통해 state 생성하고 this.setState를 사용하여 state값을 바꿨고 render를 통해 화면에 보여주었다. 18번째 줄 {this.state.count}로 화면에 보여주었으나 onClickCountUp을 하니 에러가 발생했다. -> this에 대한 이해가 필요하다.

  • 리액트의 작동원리에서 html을 직접 만들지 않는다. 만드는 것은 javascript이고 화면에 보여지는 것은 html이다. 자바스크립트로 jsx가 Html이 만들어지는 방식이다.

  • window.onload = function() {...} 은 html 코드가 읽히고 나면 등록된 함수를 실행시켜줘!

  • counter를 만들고 counter 안에 있는 render를 실행시키면, 버튼이 만들어지고 안에 '클릭하세요', onClick 눌렀을때 등록이 되고 button이 자식으로 추가가 되어 화면에 나타난다.

  • 클릭을 누르면 this.count가 undefined가 나온다.

this는 실행을 시킨 실행 주체에 따라서 동적으로 달라진다.

  • 클릭한 것은 button이라 class와 상관이 없다. 클릭했을때 실행시킨 주체가 this가 된다.
  • 여기서 실행시킨 주체는 button이므로 this는 button이 되고 this.innerText클릭하세요.가 나온다.

해결방법(this 고정 방법)
1. bind(this)를 통해 여기서 지금 사용하고 있는 this를 onClickButton에 연결시킨다.
2. onClickButton을 화살표 함수로 사용하면 된다.

  • 화살표 함수에서 사용하는 this는 눈에 보이는 것 같이 해당하는 this이다.
  • 함수에 등록된 this이면 실행될 때 실행되는 주체가 this가 된다.
  • 가끔 복잡한 경우 함수를 동적으로 실행시켜야 하기 때문에 화살표함수가 아닌 기본 함수를 써야할 때가 있기 때문에 동작 원리를 이해하고 있어야 한다.

this의 이해

  • Component 안에 기능이 내장되어 있어 이름이 반드시 동일해야 용도에 맞게 실행시켜준다.

  • componentDidMount() : 화면이 그려지고 나서 실행해라
    - ex1) input 태그가 그려지고 input 태그에 focus가 깜박깜박하도록 실행

    • ex2) 페이지 전체가 그려지고 페이지에 접속한 유저의 권한 확인
  • componentDidUpdate() : state를 올리면 바뀐 state로 화면이 리렌더(수정)되면 실행해라
    - ex) state의 count가 5가 되었을 때 특정 알림을 준다

  • componentDidWillUnmount() : 페이지를 나갈 때 지금 컴포넌트가 사라지기 전에 실행해라
    - ex) 채팅방을 나가기 버튼을 클릭했을 때 백엔드 api를 날려서 '철수가 나갔습니다.' 요청을 보낸다.

    • 굳이 여기서 말고 아래 그림과 같이 만들면 되지 않을까?

    • 결과 먼저 말하면 안된다. 이렇게 되면 채팅방 나가기 버튼을 눌러 나가는 것 이외에 상품을 보러 나가거나, 마이페이지로 이동하여 나가거나, 브라우저를 끄고 나갈 때 마다 모든 api를 요청해야 하므로 유지보수가 안된다.

    • 따라서 눈 앞에서 페이지가 사라지게 되면 componentWillUnmount가 실행되고 사라지도록 한다.

  • 왼쪽은 변수, 오른쪽에는 count가 있는 type이다.
  • 아래와 같이 IPrevState로 빼서 해도 좋다.
  • 왼쪽이 변수, 오른쪽이 타입이다.

함수형 컴포넌트 생명주기

함수형과 클래스형 차이

  • state: 클래스형에서는 반드시 state로 쓰고 객체형태로 묶여져 있으나 함수형은 자유롭게 개별 state로도 사용 가능하다.

  • setState : 클래스형에서는 this.setState를 통해서 컴포넌트에서 상속을 받아 사용했었으나 함수형은 자유롭게 만들어서 사용한다.

  • Hook : 클래스형에서 Component에서 제공하는 기능들이 함수형에서는 hook으로 대체 되었다.

  • this : 함수형에서 this가 없어 state,setState를 바로 가져다 사용할 수 있고 클래스형처럼 바로 장착 되어 있는 것이 아니기 때문에 변수형으로 만들어줘야 한다.

  • Router 기능도 함수형에서는 바로 사용할 수 없고 useRouter를 가져와야 한다.

  • 클래스형의 componentDidUpdate가 함수형의 useEffect로 대체되는데 약간 차이가 있다. componentDidUpdate는 처음에 실행 안되고 state가 변경되고 나서 실행인데, useEffect는 처음 실행되는 것도 변경으로 본다. 그렇기에 처음 실행되도 실행되고 변경되고 나서도 실행된다.

  • 아래가 기본, 의존성 배열이 없기 때문에 아무거나 바뀌면 실행된다.

  • 클래스형의 componentDidMount는 함수형의 useEffect에 조건을 달아서(의존성 배열) 실행한다

  • 그리고 한 번만 실행되고 나서 뒤로는 실행되면 안되기 때문에 의존성 배열을 빈칸으로 둔다.

  • 의존성 배열 안의 원소가 변경 되어야 실행되는데 없기 때문에 처음에만 실행되고 두 번째부터는 변경 없다.

  • componentWillUnmount는 이 컴포넌트가 사라질 때 실행시켜줘라고 등록을 시키는 것이다. 함수형 useEffect 안에서 return 에서 함수를 리턴하면 WillUnmount와 같이 등록이 된다.

  • 처음 한 번만 등록하면 되기 때문에 의존성 배열에 빈값을 넣어준다.

  • 위에 것을 하나의 useEffect로 합치게 되면 의존성 배열이 없기 때문에 한 번만 실행이 되고 의존성 배열이 바뀌어야 하는 변경되고 나서 실행은 따로 만들어줘야 한다.

  • useEffect 안에서 setState는 두 번 렌더링 되기 유지보수 차원에서 지양하는 것이 좋으나 물론 필요한 경우도 있다.

  • useEffect 안에서 setState 한 state를 의존성 배열에 들어간 경우, 바뀐 state가 또 들어가기 때문에 무한루프에 빠진다.

  • 또는 useEffect에서 setState를 사용할 때 의존성 배열이 없으면 바뀔 때마다 useEffect가 실행되는 것인데, 바뀌면 useEffect 실행되므로 무한루프에 빠진다.

// useEffect의 잘못된 사용 예제(1. 추가렌더링, 2. 무한루프)
// 1. 추가 렌더링
useEffect(()=>{
   setCount(prev=>prev+1)
},[count]);

// 2. 무한루프
useEffect(() => {
  setCount(prev=>prev+1)
});

  • 순서와 상관없이 useEffect는 화면이 그려지고 나서 실행된다.

openAPI with useEffect

react-query

restapi 사용시 graphqlapi 요청 useQuery와 같은 역할을 한다.

useEffect에서 axios 사용

  • 화면이 나오고 나서 useEffect가 실행이 되면 요청이 들어가고 setState에 들어가고 state가 변경이 되면서 화면이 리렌더 되는데, 리렌더 되고 나서 componentDidMount이기 때문에 두 번 이상 실행 안된다.
  • 위와 같은 방법이 불편하기 때문에 graphql apollo client 했던 것처럼 restAPI 방식을 사용할 수 있도록 한 것이 react-query 라이브러리이다.

open API

  • 백엔드 개발자분들이 만들어 놓은 api를 통해 데이터를 가져올 수 있다.
  • 처음에는 어려울 수 있으니 auth : no, https: yes/no, cors: no 인 것으로 진행

0개의 댓글