Lifecycle 은 클래서형에서는 compent의 메서드로, 함수형에서는 useEffect로 사용할 수 있다.

 

1. 그리기
2. 그리고 난 뒤 실행
3. 그리도 난 뒤 변경됐을 때
4. 그리고 난 뒤 사라질때

 

위의 예시처럼 a 실행시키고 바로 다음 동작을 명령시킬때 해당 동작만을 실행시킨다. 

 

이것은 코드 작성을 간편하게 하는 것도 있지만, 다음 동작을 위해 전체 코드를 리렌더링하지 않고,

원하는 부분만 인식시켜 컴퓨터를 더 효율적으로 동작시키는 장점도 있다.

 

시작하기 전에 useEffect는 전체코드를 실행한 뒤 동작되는 메서드 인 점을 기억하자

 

class형 lifecycle

 

  componentDidMount(): void {
    // Component 의 기능
    console.log("그려지고 나서 실행!!");
  }
  componentDidUpdate(): void {
    // Component 의 기능
    console.log("변경되고 나서 실행!!");
  }
  componentWillUnmount(): void {
    // Component 의 기능
    console.log("사라지기전에 실행");
    // 예시) 채팅방 나가기 API, 나가기전에 마지막으로 할 것들
  }

 

componentDidMount : 함수가 모두 그려지면 바로 실행된다. (최초 1회)

componentDidUpdate : 함수가 변경될 때마다 무한대로 실행된다.

componentWillUnmount : 해당 함수를 벗어나기 전에 1번 실행 ex) 채팅방 나가기 등

 

전체 함수에 적용하거나 함수안에 적용시켜서 사용이 가능할 것 같다.

  onClickCountUp = (): void => {
    // console.log(this.state.count);
    this.setState({
      count: 1,
    });
  };

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

  render(): JSX.Element {
    return (
      <>
        <div>{this.state.count}</div>
        <button onClick={this.onClickCountUp}>카운트 올리기!!</button>
        <button onClick={this.onClickMove}>나가기!!</button>
      </>
    );
  }

 

함수형 lifecycle

 

함수형은 Hooks 를 활용한 useEffect를 사용할 수 있다.

 

// 기본 모양

useEffect( () => { 
	실행시킬 함수 작성 
    },[ 반복 횟수 작성 ]);

 

" 반복 횟수 작성 " 공간에 아무것도 작성하지 않으면 의존성 배열로 초기에 한번만 실행되고 실행되지 않습니다.

" 반복 횟수 작성 " 공간 자체가 없을 경우 무엇이 바뀌던 바뀔때마다 무한적으로 다시 실행 시킵니다.

 

이때 componentDidUpdate와 다른점은, 처음 Mount 됐을 때도 한번 실행된다는 점입니다.

 

// useEffect 활용

useEffetc( () => {
	console.log("그려지고 나서 실행!!")
    
    return () => {
    console.log("사라지기전에 실행!!");
    };
});

이렇게 "실행시킬 함수 작성" 공간에 return 을 추가하게 되면, 마치 class형의 componentWillUnmount  와 비슷하게 동작합니다.

 

 

useEffect의 잘못된 사용 방법 

useEffect는 코드 순서와 상관없이 함수를 모두 그린 후 실행되는 특징을 가지고있습니다.

그럼 만약에 useEffect안에서 set을 사용하여 변수의 값을 변경시키면 어떻게 될까?

 

  useEffect(() => {
    setCount((prev) => prev + 1);
  }, [count]);

위 함수처럼 count 값이 변경될때마다 useEffect를 반복하고, useEffect는 계속해서 count + 1을 실행하므로 무한 루프에 빠지게 된다.

지금까지 자바스크립트, 타입스크립트를 학습하면서 아래 형식을 기본적으로 사용하였다.

 

export default function 함수명 () {
 // 자바스크립트
	return ();
 // HTML   
    }
    
    // 함수형 컴포넌트

예전에는 함수형 컴포넌트에서 상태를 관리할수가 없었는데, Hook의 출현으로 상태 관리가 가능해졌다. useEffect도 없었으니 렌더링 전후로 어떤 작업을 하고 싶어도 할수가 없었다. 그래서 사용한 것이 클래스형 컴포넌트이다.

 

 

그래도 클래스형 컴포넌트를 활용할 기회가 생길 수 있으니, 어떻게 사용하는지 알아보자

 

1.  사용 방법 :  함수형과 다르게 클래스형은 함수와 변수를 사용할때 const, let, function 등을 사용하지 않습니다.

class Monster {
  power = 50;
  attack(): void  {
    console.log("공격합니다!!");
  }
}

2.  상속과 오버라이딩 : 미리 선언한 함수에 기능을 추가하거나 다시 정의할 수 있습니다. 

// 클래스 상속 : 기존 클래스에 기능을 추가해서 만든 클래스
class SuperMonster extends Monster {
  run(): void {
    console.log("도망가자!!");
  }

  // 오버라이딩: Monster의 메소드를 다시 정의해서 덮어씌운다.
  attack(): void {
    console.log("슈퍼 몬스터 필살기!!");
  }
}
const monster = new Monster();
console.log(monster.power); // 50
monster.attack(); // 공격합니다!!

const supermonster = new SuperMonster();
console.log(supermonster.power); // 50
supermonster.attack(); // 슈퍼 몬스터 필살기!!

 

class형 컴포넌트 사용 예시

import { Component } from "react";

export default class ClassCounterPage extends Component {
  // extends를 사용하여 리액트 기능 중 하나인 Component를 상속 받습니다.
  state = {
    count: 5,
  };

  // 화살표 함수로 변경하여 this 사용
  onClickCountUp = (): void => {
    // 변경전 onClickCountUp(): void {
    console.log(this.state.count);
    this.setState({
      count: 1,
    });
  };

  // render 작성 (정해진 규칙)
  render(): JSX.Element {
    return (
      <>
      {/* this는 class 자기자신을 뜻합니다. */}
        <div>{this.state.count}</div>
        
        {/* 직접 바인딩할 때는 onClick={this.onClickCouter.bind(this)} 라고 적어주셔야 합니다. */}
        <button onClick={this.onClickCountUp}>카운트 올리기!!</button>
      </>
    );
  }
}

 

this

함수형에서는 보이지 않던 this가 자주 사용된 것을 볼 수 있다.

이때 this 는 선언했던 변수를 함수에 가져오는 방법이라고 생각하면 좋을 것 같다.

 

그러나 this를 어디서 실행하느냐에 따라 변화하는 이슈가 있다 (동적 this)

 

변수를 가져오는 함수를 선언할때 함수표현식으로 선언하면 정상적으로 이전의 this를 받아오지 못한다. (this 자체가 함수로 변경되는 이슈가 생김 ex) onClickCounter 클릭시 this가 onClickCounter로 변경됨

 

그래서 함수를 선언할때 화살표 함수로 선언하거나 .bind(this)를 사용하여 this를 class로 고정해야한다.

 

onClick을 가진 부모태그가 있다.

그리고 또다른 onClick 함수를 가진 태그를 자식태그로 넣었을때를 가정해보자.

 

가장 최상위에 있는 부모태그를 클릭할 경우 자식은 클릭되지 않았으니, 부모의 onClick 함수만 작동 될 것이다.

그러나 부모에게 포함되어있는 자식을 클릭할 경우는 어떻게 될까??

 

아래 함수로 확인해보자

export default function StaticRoutingMovedPage() {
const qqq1 = () => {
    alert("1번 클릭");
  };

  const qqq4 = (event: any) => {
    event.stopPropagation();
    alert("4번 클릭");
  };

  return (
    <div>
      {data?.fetchBoards.map((el: any) => (
        <div id={el.writer} onClick={qqq1}>
          <Checkbox />
         
         
         {/* import해서 가져오는 경우에도 자식에 들어가게 된다면, 
          클릭기능에 반드시 event.stopPropagation을 놓치지 않고 작성해야 합니다. */}

          {/* <span onClick={qqq2}><input type="checkbox" onClick={qqq3} /></span> */}



          <span style={{ margin: "10px" }} onClick={qqq4}>
            {el.number}
          </span>
          <span style={{ margin: "10px" }}>{el.title}</span>
          <span style={{ margin: "10px" }}>{el.writer}</span>
        </div>
      ))}
    </div>
  );
}

 

 

아래는 currentTarget을 이용한 예시이다.

import { useQuery, gql } from "@apollo/client";
import { MouseEvent } from "react";

const FETCH_BOARDS = gql`
  query {
    # fetchBoard(number: 1)
    fetchBoards {
      number
      writer
      title
      contents
    }
  }
`;

export default function StaticRoutingMovedPage() {
  const { data } = useQuery(FETCH_BOARDS);

  const onClickAlert = (event: MouseEvent<HTMLDivElement>) => {
    // alert(event.target.id);
    // 태그에 id값이 없는곳을 클릭하면 id가 없으므로 아무것도 출력되지 않습니다.

    alert(event.currentTarget.id); //currentTarget은 무조건여야 합니다.
    // 자식을 포함한 부모의 아무곳이나 클릭해도 id 값을 가져올 수 있습니다.
    // 부모와 자식에게 모두 서로 다른 onClick 함수가 있을경우, 자식의 onClick을 클릭하면 부모의 onClick까지 실행됩니다. (propagation:전파)
  };

  return (
    <div>
      {data?.fetchBoards.map((el: any) => (
        <div id={el.writer} onClick={onClickAlert}>
          <span style={{ margin: "10px" }}>{el.number}</span>
          <span style={{ margin: "10px" }}>{el.title}</span>
          <span style={{ margin: "10px" }}>{el.writer}</span>
        </div>
      ))}
    </div>
  );
}

변수를 useState로 담게 되면 state는 함수가 끝날때 마지막으로 선언된 값을 가져온다.

 

아래와 같이 선언 할 경우 마지막을 제외한 결과 값들은 임시 저장공간에 저장만 되며,

버튼을 클릭했을때 결국에는 마지막의 +2만 적용된다.

    function onClickCountUp():void{
      setCount(count + 2)
      setCount(count + 1)
      setCount(count + 3)
      setCount(count + 5)
      setCount(count + 2)
      //setState의 특징으로(임시저장공간) 마지막 카운터만 ( +2 ) 적용됩니다.

 

그러나 prev를 사용하게되면 임시공간에 저장한 값을 버리지 않게 된다. 

 

import { useState } from "react";

export default function PrevstatePage() {
  const [state, setState] = useState(0);

  function sumAll() {
    setState((prev) => prev+1) ;
    setState((prev) => prev+2);
    setState((prev) => prev+3);
    setState((prev) => prev+4);
  }

  return (
    <>
      <div>결과는: {state}</div>
      <button onClick={sumAll}>실행!</button>
    </>
  );
}
	//한번 클릭할때마다 1+2+3+4 인 10을 더하게됩니다.

 

템플릿 리터널은 내장된 표현식을 허용하는 문자열 리터럴입니다.

const name = "철수"
const age = 12

//기본 방식
console.log(name + "는" + age + "살 입니다") //'철수는12살 입니다'

//템플릿 리터널
console.log(`${name}는 ${age}살 입니다.`) //'철수는 12살 입니다.'

이렇게 ``안에 문자열과 변수를 함께 사용하며 띄어쓰기도 모두 그대로 적용할 수 있으며,

${}안에는 변수와 연산자 ( +, -, *, /, 등) 도 모두 사용할 수 있다.

 

 

'리액트' 카테고리의 다른 글

클래스형(Class) 컴포넌트와 함수형(Functional) 컴포넌트  (0) 2023.02.05
state prev는 무엇일까?  (0) 2023.01.29
try ...catch 사용하기  (0) 2023.01.24
Git 명령어  (0) 2023.01.24
import와 Export  (0) 2023.01.24

try...catch 문은 실행할 코드블럭을 표시하고 예외가 발생할 경우의 응답을 지정합니다.

 

try안에는 실행될 선언들을 작성하고, catch에는 try에서 예외 즉, 오류가 발생하여 실행하지 못하게 될 경우 에러메세지로 경고 알림을 줄 수 있습니다.

 

try는 세가지 형식이 존재합니다.

 

try...catch : try 블록 안에서 예외가 발생(throw)하는 경우 무엇을 할지 명시하는 코드

try...finally :  try 블록과 catch 블록(들)이 실행을 마친 후 항상 실행됩니다. 
예외가 발생했는지에 관계없이 항상 실행

try...catch...finally : 하나 이상의 try 문을 중첩 할 수 있습니다. 내부의 try 문에 catch 블록이 없으면, 
둘러싼 try 문의 catch 블록이 입력됩니다.

 

'리액트' 카테고리의 다른 글

state prev는 무엇일까?  (0) 2023.01.29
Template Literals (템플릿 리터널 : ``)  (0) 2023.01.24
Git 명령어  (0) 2023.01.24
import와 Export  (0) 2023.01.24
JSX 란?  (0) 2023.01.24

출처 : 코드캠프

 

'리액트' 카테고리의 다른 글

Template Literals (템플릿 리터널 : ``)  (0) 2023.01.24
try ...catch 사용하기  (0) 2023.01.24
import와 Export  (0) 2023.01.24
JSX 란?  (0) 2023.01.24
Destructuring Assignment, 구조분해할당  (0) 2023.01.24

jsx를 학습하면서 자연스럽게 import와 export를 사용하였는데 이 두가지의 차이점은 무엇일까?

 

export : 내보내기

import : 가져오기

 

export를 사용하면 상수나 함수를 내보낼 준비가 완료된 것 입니다.

export default function PortFolioMoved() {
  return (
    <div>
      <PortFolioQueryContainer />
      <PortFolioMovedComments />
    </div>
  );
  
  //PortFolioMoved 함수를 내보낼 수 있습니다.

 

만약 export 뒤에 default가 있다면 해당페이지에서 유일하게 내보낼 수 있는 함수가 됩니다.

따라서 import할때 { } 를 사용하지 않고 받아야 합니다.

 

import PortFolioMoved from "./BoardsWrite.presenter";

//"" 안에 PortFolioMoved가 있는 경로를 입력합니다.
// 경로안에 PortFolioMoved가 export default로 작성됨
import {
  CREATE_BOARD_COMMENT,
  FETCH_BOARD_COMMENTS,
  DELETE_BOARD_COMMENT,
} from "./BoardsWrite.queries";

//여러가지 변수를 가져올 수 있다면 { } 안에 ,를 사용하여 가져올 수 있습니다.

 

 

함수 뿐아니라 스타일 태그 또한 같은 방법으로 불러올 수 있습니다.

여기서 * as S from 을 사용하였습니다.

위처럼 가져올 것이 많으면 import * as <obj> 처럼 객체 형태로 원하는 것들을 가지고 올 수 있습니다.

'리액트' 카테고리의 다른 글

try ...catch 사용하기  (0) 2023.01.24
Git 명령어  (0) 2023.01.24
JSX 란?  (0) 2023.01.24
Destructuring Assignment, 구조분해할당  (0) 2023.01.24
Conditional-rendering, 리액트 조건부 렌더링  (0) 2023.01.24

JSX란 무엇일까?

 

JSX(JavaScript XML)는 JS에서 XML을 확장한 문법입니다.

 

JS 뿐 아니라 HTML를 동시에 작성할 수 있기때문에 .html, .css 파일을 따로 만들 필요가 없습니다.

최근에는 파일명을 jsx가 아닌 js만 작성해도 문제 없이 동작합니다.

 

typeScript는 ts 뿐아니라 tsx까지 적어서 파일을 구별해줘야 한다는 부분에서 js만 작성하는 것은 매우 유용한 것 같습니다.

 

아래 jsx 기본 작성 방법입니다.

export default function NewBoardPage() {

	//자바스크립트 작성 부분

	return (
    
    //html 작성 부분
    
    );
}

 

css도 해당 페이지에 직접 적용할 수 있으나, 가독성을 위해 또다른 페이지를 만들고 import 기능을 활용하여 꾸며줄 수 있습니다.

 

 

 

 

 

'리액트' 카테고리의 다른 글

Git 명령어  (0) 2023.01.24
import와 Export  (0) 2023.01.24
Destructuring Assignment, 구조분해할당  (0) 2023.01.24
Conditional-rendering, 리액트 조건부 렌더링  (0) 2023.01.24
map, filter, every 활용  (0) 2023.01.24

자바스크립트를 사용하면서 구조분해할당을 사용할 수 있다.

 

구조분해할당은 배열 및 객체의 value값을 분해하여 불러오거나 변경하는데 유용하게 사용할 수 있따.

let [a,b] = [2, 10];
console.log(a); // 2
console.log(b); // 10
let arr = [1,2,3,4,5,6]
let [a,b,c,...rest] = arr
console.log(rest) // [4,5,6]
console.log(a) // 1
console.log(b) // 2

...rest를 사용하면 위와 같이도 활용이 가능하다.

 

또한 배열에서 구조분해할당을 이용하면 아래 처럼 활용이 가능하다.

//변경전

const arr = [1,2,3]
const a = arr[0];
const c = arr[2];
console.log(a,c);
//구조분해할당 활용

const arr = [1,2,3];
const [a,b,c] = arr
console.log(a,c) // 1 3

 

 

구조분해할당은 배열안에 객체에서도 사용할 수 있다.

const obj = { name: "철수", age:20, school: "다람쥐초등학교"}
const {name, age, school} = obj;

console.log(name) // '철수' 
console.log(age) // 20

또한 배열에서처럼 rest를 활용하여 뒤에 오는 key와 value만 뽑을 수 도있다.

const obj = { name: "철수", age:20, school: "다람쥐초등학교"}
const {name, ...rest} = obj;

console.log(name) // '철수'
console.log(rest) // { age: 20, school: '다람쥐초등학교' }

 

 

'리액트' 카테고리의 다른 글

import와 Export  (0) 2023.01.24
JSX 란?  (0) 2023.01.24
Conditional-rendering, 리액트 조건부 렌더링  (0) 2023.01.24
map, filter, every 활용  (0) 2023.01.24
TypeScript와 JavaScript  (0) 2023.01.19

+ Recent posts