본문 바로가기
REACT

[React] 272샘의 React11 ( useState Hook )

by 미눅스[멘토] 2024. 10. 10.
728x90

 

 

 

https://deahan.tistory.com/430

 

[React] 272샘의 React10 ( 레이아웃, children )

https://deahan.tistory.com/429 [React] 272샘의 React9 ( Props 구조 분해 )https://deahan.tistory.com/428 [React] 272샘의 React8 ( Props 이해 사용 )https://deahan.tistory.com/427 [React] 272샘의 React7 (블락 기호 {} 사용)https://deahan

deahan.tistory.com

까지 읽었다면, 

이제  저 유명한 거의 모든 React책이나, 사이트등에서 만드는 카운터 예제

조금 더 심플하게 만들어 볼 때가 되었다.  중요한 부분이니 고도로 집중하여 보자.

 

아래 코드를 작성해 보장. (집중!)

 

Counter.css

 
.counter {
    width:70%;
    min-width:300px;
    border:5px groove orange;
    margin:50px auto;
}

.counter > h2 {
    color:blueviolet;
}
.counter > h1 {
    color: red;
    font-size: 4em;
}

 

Counter.jsx

 
import PropsType from "prop-types";
import "./Counter.css";

Counter.propTypes = {
  title: PropsType.string.isRequired,
};

function Counter({ title }) {
  console.log("체킁:", "경민 만세 호출됨");

  // 카운트 변수
  let myCount = 0;

 // 클릭 이벤트 처리 함수(이벤트 핸들러)
  const fCnt = () => {
    alert("console 확인");
    myCount++;
    console.log("체크:", "미누 왕만세");
  };

  return (
    <div onClick={fCnt} className="counter">
      <h2>{title}</h2>
      <hr />
      <h1>{myCount}</h1>
    </div>
  );
}

export default Counter;
 

onclick 이 아니고, onClick임에 주의. html이 아니고, 한번 더 해석되는 JSX다.

 

App.jsx  (결과 확인용)

 
import Counter from "./Counter";

function App() {
  return (
    <div>
      <Counter title={"경민 클릭 카운터"} />
    </div>
  );
}

export default App;

 

결과는 조작하지 않았다면 아래와 같음

[ console의 경민 만세 호출됨 부분을 꼭 기억해 두자 ]

클릭해도 당연히 화면에 보이는 숫자는 계속 0 이다.

 

자바스크립트를 꽤 아는 사람은 바로 

 Counter.jsx 를  아래 처럼 수정 하고 기뻐할것이 뻔하다.


import PropsType from "prop-types";
import "./Counter.css";

Counter.propTypes = {
  title: PropsType.string.isRequired,
};

function Counter({ title }) {
  console.log("check:", "경민 만세 호출됨");

  let myCount = 0;

  const fCnt = () => {
    alert("console을 확인");
    myCount++;
    console.log("check:", "미눅스 만세");

    /* 추가한 부분 */
    document.querySelector(".aaa").innerHTML = myCount;
  };

  return (
    <div onClick={fCnt} className="counter">
      <h2>{title}</h2>
      <hr />
      { /* class aaa 추강 */ }
      <h1 className="aaa">{myCount}</h1>
    </div>
  );
}

export default Counter;
 

결과는 아래 처럼 잘 될게 뻔함. [ console의 경민 만세 호출됨 부분을 꼭 기억해 두자 ]

 

하지만  이것은 React가 원하는 모습이 아니었다.

[ 이 방식을 개선하려 했던 것이였는데 이렇게 쓰면 그저 참담하다.]

여기서 React는 useState라는 Hook을 쓰라 한다.  일단 먼저 써보자.

 

 Counter.jsx 에 useState Hook을 적용하여 수정

 
import PropsType from "prop-types";
import "./Counter.css";
/*추가 된 부분 */
import { useState } from "react";

Counter.propTypes = {
  title: PropsType.string.isRequired,
  fsum: PropsType.func.isRequired,   // 추가된 부분
};

function Counter({ title,fsum }) { //바뀐부분
  console.log("check:", "경민 만세 호출됨");

  /* 바뀐 부분 */
  let [myCount, setMyCount] = useState(0);

  const fCnt = () => {
    alert("console을 확인");
    setMyCount((myCount) => myCount + 1);
    console.log("check:", "미눅스 만세");
  };

  return (
    <div onClick={fCnt} className="counter">
      <h2>{title}</h2>
      <hr />
      <h1>{myCount}</h1>
    </div>
  );
}

export default Counter;

결과는 이전과 같은 데엥, console에 찍힌 게 먼가 의미 심장하다

 

클릭 할때마당, 경민 만세 호출됨이 console에 찍힌다.  무신 의미 일까

Counter 함수가 통째로 다시 불렸다는 의미는? .... Counter 컴포넌트가 다시

만들어졌다는, 곧 다시 그려졌다는(re-rendering 되었다는) 의미!!

 

자주 사용되는 아래 형식을 기억하자.  React에서 제공하는 useState Hook(훅) 사용법이다.

const [myCount, setMyCount] = useState(0);
//           변수명      ,함수명           =  useState(초기값)

myCount는 변수명이고 setMyCount는 myCount 변수에 값을 세팅하는 함수인데,

관례적으로 set변수명(변수명 첫글짜는 대문자)으로 정하고, useState의 ()안의 값은

myCount 변수의 초기값이다.  애매하다면 일단 사용법 기억만으로 만족해도 좋다!

 

useState로 사용한 myCount 같은 변수를 React에선 멋진 말로 Reactive 변수라 

일컫는데, 이 값이 바뀌게 되면 React는 해당 컴포넌트를 다시 그린다.

[타짜 손보다 빨라 웬만해선 눈으로 볼 수 없다. ]

 

자바스크립트를 공부한 흔적을 조금 쌓은 사람이라면 위의 형식이 구조분해가 

사용된 형식임을 본능적으로 졸다가도 느낌이 온다.  아래 코드 눈으로 휙하고 느낌만 받자.


  // useState 사용이 구조분해임을 보여주는 심플 가짜코드
  function useState(initV) {
    // 배열에 값과 함수를 담아서 리턴
    return [initV, function () {}];
  }

  const [count, setCount] = useState(0);
 

React에서 제공하는 Hook(훅) 함수들의 공통점은 앞에 use를 붙여서 사용하기 때문에 

금방 알아챌 수 있다. 그럼 Hook 함수란 무엇인가?

 

Hook 함수 덕분에 class 키워드 사용이 거의 필요없고 function 컴포넌트로 편하게 

바뀌게 되었는데,  Hook은 버젼 16.8 부터 추가 되었다.

컴포넌트의 상태값에도 접근할 수 있고, 컴포넌트가 새로 html문서에 붙거나(mount)

사라지거나(unmount) 등의 이벤트 처리등도 Hook 함수로 편하게 처리 할 수 있다.

이 시점에선 그냥 React에서 제공해 주는 편리한 함수정도로 일단 만족하자!

 

여기서 뇌를 쪼금 자극하는 방향으로 한발짝 더 나아가 보자.

 

App.jsx   일부러 여기서 시작한거당. top -> down 흐름이 보이도록

 
import { useState } from "react";
import Counter from "./Counter";

function App() {
  const [sum, setSum] = useState(0);

  return (
    <div>
      <Counter title={"경민 클릭 카운터"} fsum={setSum} />
      <Counter title={"미누 클릭 카운터"} fsum={setSum} />
      <Counter title={"선주 클릭 카운터"} fsum={setSum} />
      <h1>
        모두의 클릭수는 {sum} 이다
      </h1>
    </div>
  );
}

export default App;
 

위 코드를 보면 바로 눈치 채겠지만 . 각각의 Counter를 클릭한 수를 합한

sum을 추가로 표시할 생각임.

Counter의  Props의 속성명 fsum으로 setSum  함수를 넘겼다

 

Counter.jsx 도 위에 맞게 당연히 수정되어야 한당.

 
import PropsType from "prop-types";
import "./Counter.css";
/*추가 된 부분 */
import { useState } from "react";

Counter.propTypes = {
  title: PropsType.string.isRequired,
  fsum: PropsType.func.isRequired,   // 추가된 부분
};

function Counter({ title,fsum }) { //바뀐부분
  console.log("check:", "경민 만세 호출됨");

  /* 바뀐 부분 */
  let [myCount, setMyCount] = useState(0);

  const fCnt = () => {
    alert("console을 확인");
    setMyCount((myCount) => myCount + 1);
    console.log("check:", "미눅스 만세");
    fsum((sum)=> sum +1);           //추가된 부분
  };

  return (
    <div onClick={fCnt} className="counter">
      <h2>{title}</h2>
      <hr />
      <h1>{myCount}</h1>
    </div>
  );
}

export default Counter;


결과를 눈으로 확인하자.~~(각각 클릭해 보면 잘 될것이다!)

정리를 조금 해보자.

fCnt 함수안에서 fsum(실제는 setSum함수를 가리킴)을 이용하여

원래 가진 sum값을 +1씩 증가 시킨다.

useState가 return하는 setXXX함수의 매개변수 콜백함수  preVal => preVal +1 의 

매개변수 preVal은 바로 이전 상태의 값을 가지고 있다.

(받아들이자.. 그렇게 설계 되었다.. 시르면 본인만 힘들다.~~  )

아래 내용은 설마하는 노파심에 적어본다.~~ (화살표 함수)

/*
  아래 fCk1과 fCk2는 같은 의미다.
*/
const fCk1 = preVal => preVal+1

function fCk2(preVal){
    return preVal + 1;
}
 

fsum: PropsType.func  단지 fsum은 함수타입이어야 한다는 의미다..

 

간단한 예제지만 의미는 아주 아주 중요하다.( 조금이라도 감을 잡아보자) 

정보는 부모에게서 자식 방향으로만 흐른다고 초반에 꼭 기억하라 하였다.

지금 sum값을 출력하는 것은 App에 있고, 이벤트 발생은 Counter에 있다.

자식 컴포넌트의 이벤트로 부모안의 값을 바꾸었다.(거꾸로다...훌륭하다!~~  오케이?? )

그리고 기억해라..

부모의 상태가 바뀌고 다시 그려지게 되면 자동으로 자식도 다시 그려진다.

 

 

 

출처 : https://e-7-e.tistory.com/259