programming language/react

[React] Props와 State 이해하기 / Hook(useState, useEffect) 적용

공대키메라 2022. 6. 7. 23:16

저번 시간에 React란 무엇인지, 그리고 장점이 무엇인지 알아봤고 

 

마지막에는 boilder plate를 활용해 쉽게 React 프로젝트를 생성하는 법을 배웠다. (지난 정리가 궁금하다면? 클릭!)

 

이번 시간에는 React에서 꼭 알아야 하는 State와 Props에 대해 알아보겠다.

 

코드는 지난 시간에 이어서 기존에 추가하는 방식으로 진행할 것이다. 

 

해당 내용은 다음 사이트에서 참고했다.

 

참고

https://ko.reactjs.org/docs/components-and-props.html

https://ko.reactjs.org/docs/hooks-rules.html

https://ko.reactjs.org/docs/hooks-state.html

https://xiubindev.tistory.com/100


1. Props란?

Props에 대해 알기 위해 먼저 바로 코드를 보도록 하겠다.

App.js

import "./App.css";
import Header from "./Header";

function App() {
  let name = "키메라 끼에ㅔ엥ㄱ";
  return (
    <div className="App">
      <Header text={"text"} />
      <header className="App-header">hello React! with... {name}</header>
    </div>
  );
}

export default App;

 

Header.js로 컴포넌트를 지난 시간에 만들었는데 저번과 다르게 text ={"text"}라는 것이 Header tag안에 입력되어 있다.

 

props는 특별한게 아니라 Properties의 줄임말이다. 우리가 원하는 속성을 안에 설정해서 넘겨줄 수 있다는 말이다. 

 

그러면 Header.js 에서는 어떻게 받아야 하는건가?

Header.js

const Header = ({ text }) => {  
  return <div>header : {text}</div>;
};

export default Header;

 

이렇게 해주면 된다. 

 

그러면 화면에 다음과 같이 출력될 것이다.

 

 

무조건 작게 넘겨줘야 하냐고? 아니다! 그러니까... 받는 곳에서 어떤 값을 받을 것인지 정확히 입력을 안해도 우선 값이 넘어간다는 말이다. 

App.js 수정

import "./App.css";
import Header from "./Header";

function App() {
  let name = "키메라 끼에ㅔ엥ㄱ";
  return (
    <div className="App">
      <Header text={"text"} name={"thelovemsg"} />
      <header className="App-header">hello React! with... {name}</header>
    </div>
  );
}

export default App;

 

Header.js 수정

const Header = (datas) => {
  console.log(datas);
  return (
    <div>
      header : {datas.text} & {datas.name}
    </div>
  );
};

export default Header;

 

datas는 객체로 넘어오는데 객체에 name, text에 대한 내용이 담긴 것을 확인할 수 있었다.

그러면 화면에 나오는 결과는 다음과 같다. 

 

우리가 평소에 javascript를 다루면 객체를 직접 많이 다룰 일이 빈번하다. 

 

그래서 props를 조작하려고 할 수도 있는데 props는 안타깝게도(킹받네....) 읽기 전용이다. 

 

React 공식 사이트에서는 props에 대해 다음과 같이 설명하고 있다.

 

모든 React 컴포넌트는 자신의 Props를 다룰 때 반드시 순수 함수처럼 동작해야 합니다.

 

순수함수? Innocent Function? (올ㅋ)

 

순수 함수란 입력값을 바꾸지 않고 항상 동일한 입력값에 대해 동일한 결과를 반환하는 함수이다. 

 

React 공식 사이트에서는 현재에서 할 수 있는 예를 하나 더 보여준다. 

App.js - 타이머

import React from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
const root = ReactDOM.createRoot(document.getElementById("root"));
function result() {
  const element = (
    <div>
      <h1>Hello, world!</h1>
      <h2>It is {new Date().toLocaleTimeString()}.</h2>
    </div>
  );
  root.render(element);
}
setInterval(result, 1000);

 

 

시간이 위 처럼 하면 계속 흘러가는데 이것을 component로 뺴면 어떻게 해야 할까?

 

물론 다음처럼 가능하다. 

App.js - Header component에 date props 추가

import "./App.css";
import Header from "./Header";
import Clock from "./Clock";

function App() {
  let name = "키메라 끼에ㅔ엥ㄱ";
  return (
    <div className="App">
      <Header text={"text"} name={"thelovemsg"} date={new Date()} />
      <header className="App-header">hello React! with... {name}</header>
    </div>
  );
}

export default App;

Header.js - date props 추가

const Header = (datas) => {
  console.log(datas);
  return (
    <div>
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {datas.date.toLocaleTimeString()}</h2>
      </div>
      header : {datas.text} & {datas.name}
    </div>
  );
};

export default Header;

 

그렇게 나온 화면이 다음과 같다.

 

 

여기서 문제가 있는데... 시간이 계속 흘러야 하는데 오후 10:13:46에 가만히 멈추고 있다.

 

우리가 새로 고침을 해야만 시계가 움직인다. 무언가 잘못됐다... 하지만 좀 전에 props의 특징이 무엇이라고 했는가? 

 

모든 React 컴포넌트는 자신의 Props를 다룰 때 반드시 순수 함수처럼 동작해야 합니다.

 

현재 문제점은 시간이 저절로 흐르도록 해야 하는데 props의 한계로 불가능하다.

 

그냥 자식 컴포넌트들은 값을 전달받을 뿐이지 어떻게 우리가 props를 조작할 수가 없다.

 

여기서 필요한 것이 state이다. 

2.State란?

React에서 상태란 계속해서 변화하는 특정 상태이다. 상태에 따라 각각 다른 동작을 하도록 함에 목적을 둔다.

 

여기서 state는 어떻게 관리하냐면 useState라는 React에서 지원해주는 method를 이용해서 관리한다. 

 

React에는 Hook이라는 것이 있는데, 거의 99.9퍼센트 왠만하면 Hook을 이용해서 React 작동시킨다. 

 

Hook은 함수 컴포넌트에서 React state와 생명주기 기능(lifecycle features)을 “연동(hook into)“할 수 있게 해주는 함수다.

 

Hook은 class 안에서는 동작하지 않지만, class 없이 React를 사용할 수 있게 해준다.

 

Hook 에는 여러가지 종류가 있는데 오늘은 useState, useEffect에 대해서만 알아볼 것이다. 

 

Hook이 뭐가 있는지 더 궁금하면 다음 그림을 보고 사이트를 참조하면 된다.

https://ko.reactjs.org/docs/hooks-reference.html

 

Header.js 수정 - useState, useEffect 적용

import { useEffect, useState } from "react";

const Header = (datas) => {
  console.log(datas);

  const [time, setTime] = useState(new Date());
  useEffect(() => {
    const id = setInterval(() => {
      setTime(new Date());
    }, 1000);
    return () => clearInterval(id);
  }, []);

  return (
    <div>
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {time.toLocaleTimeString()}</h2>
      </div>
      header : {datas.text} & {datas.name}
    </div>
  );
};

export default Header;

 

useState는 state변수를 선언할 수 있고, 이 state변수를 갱신할 수 있는 함수를 반환한다. 

 

초기값을 useState에 넣어주면 time에 들어가는 것이다. 

 

useEffect는 componentDidMount, componentDidUpdate, componentWillUnmount를 합친 것이다. 

 

좀 더 설명하자면 useEffect를 통해서 React  의 생명 주기를 관리할 수 있다는 말이다. 

 

https://www.zerocho.com/category/React/post/579b5ec26958781500ed9955

 

순서대로 이름에서 보이듯이 역할을 말하자면 component가 rendering된 후, component가 update된 후, component가 사라진 후 이벤트를 세개로 관리가 가능하다. Class로 React를 관리하는 경우 이 세가지 함수가 필요하지만 우리는 Hook을 이용해서만 사용할 것이다.

 

사실 React자체에서도 Class로 하는 것의 단점을 인식해서 Hook으로 사용하길 권장한다(그냥 닥치고 쓰라는 말이다

 

다만, 기존에 Class 를 Hook과 조화롭게 사용할 수 있도록 지원하겠다고 한다. 

 

후후... 하여간....

 

사용법을 간단히 정리하면 다음과 같다.

useEffect 사용법 정리

useEffect(function, deps)
- function : 수행하고자 하는 작업
- deps : 배열 형태로 검사하고자 하는 값 혹은 빈 배열을 넣어준다.

useEffect(() => {
 console.log('마운트 될 때만 실행')
}, [])

useEffect(() => {
 console.log('렌더링 될 때 마다 실행')
})

useEffect(() => {
 console.log('배열에 입력한 값이 업데이트 될 때 실행')
}, [props나 state 배열로 입력])

이번에는 props, state를 이해하는 시간을 가졌고, useState, useEffect를 어떻게 써야 하는지 알아봤다.

 

사실 어느정도 내가 알아보고 사용할 정도로 정리하는 성격이 강하기 때문에 이해가 안되는 부분이 있을 수 있다. 

 

그 점은 양해 바라고 피드백은 언제든지 환영한다.