본문 바로가기
FE/React

React state, prev & props, children

by ideal_string 2022. 9. 17.

별도 상태관리 라이브러리를 사용하지 않는다면 리액트에서 함수 다음으로 많이 사용하는 게 바로 state인 듯하다. 모달을 열고 닫을 때나, 어떤 값을 저장하고 뺄 때나, 특정 변화를 자식 컴포넌트에서 작동 시키고 싶을 때 등 state가 항상 쓰인다.

state는 값을 저장하는 변수와 저장 값을 업데이트할 수 있는 함수가 한쌍으로 이뤄져있다. 한 단어로 말한다면 상태관리기능이다. 리액트에서는 이를 hook이라 부른다. (hook은 특정 기능을 수행하는 함수 또는 기능 모음을 가리키는 리액트 용어다.) state는 말로 설명하기보다 코드로 보는 게 이해가 빠르므로 코드부터 보자.

useState

import { useState } from "react";

export default function CounterStatePage() {
  const [count, setCount] = useState(0);

  function onClickCountUp() {
    setCount(count + 1);
  }

  return (
    <>
      <div>{count}</div>
      <button onClick={onClickCountUp}>카운트 올리기!!!</button>
    </>
  );
}

위 코드는 버튼을 누르면 값이 1씩 증가해 화면에 출력한다. state를 사용하기 위해서는 먼저 useState기능을 가져온다.

import { useState } from "react";

 

리액트 기본 페이지를 만든 후 안에  useState를 선언한다.

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

디스트럭쳐링하듯  useState에서 두가지를 불러오는데, 왼쪽에 있는 건 변수, 오른쪽에 있는 건 상태 변경하는 함수라 생각하면 된다(여기서는 표기상 동작함수라 부르겠다). 여기서는 count로 명명한게 값이 담길 변수고, setCount는 count 값을 변경시킬 동작함수다. 이름은 마음대로 바꿀 수 있으며, 동작함수인 두번째 요소는 set을 붙이는게 관례다. useState() 괄호 안에는 초기값을 설정한다 0을 넣으면 숫자 ""를 넣으면 문자열로 초기값이 설정된다. 객체나 배열 등 다 가능하다.

  return (
    <>
      <div>{count}</div>
      <button onClick={onClickCountUp}>카운트 올리기!!!</button>
    </>
  );

화면에 버튼을 만들고 클릭하면 onClickCountUp함수를 실행하게 했다. 

  function onClickCountUp() {
    setCount(count + 1);
  }

onClickCountUp함수는 setCount함수를 실행시키면서 count 값으로 반영 시킬 값을 적었다. 그럼 클릭할 때마다 count 값이 계속 변경되면서 화면에 변경된 값이 출력된다. 이때 화면에 출력되는 이유는, state는 상태가 바뀌면 해당 화면을 다시 리렌더링하기 때문에 버튼을 누를때마다 화면에 숫자가 증가하는 게 보인다.

 

Prev

state 함수 부분에서 쓸 수 있는 기능이 하나 있다. 바로 이전 값을 가져오는 prev다. state 실행은 동작함수가 여러개 실행 되더라도 같은 함수는 모았다가 한 번에 실행된다.

  function onClickCountUp() {
    setCount(count + 1);
    setCount(count + 1);
    setCount(count + 1);
  }

위 코드 처럼썼을 경우 버튼을 눌렀을 때 3씩 늘어나는게 아니라 1씩 늘어난다. state 동작함수는 한 스코프 안에서 한 번만 실행되도록 만들어졌기 때문이다. 위 코드대로 라면 첫 번째 setCount를 바꾸겠다고 컴퓨터가 기억하고 있는 상태고, 두번째 setCount가 들어오면 "아, 그렇게 바꾸라고?"하고 기존 것을 버리고 두번째 setCount 기억한다. 세번째 함수도 마찬가지. 저 함수 처리가 한 스코프 내에서도 다 동작하게 하고 싶을 때 prev가 등장할 시점이다.

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

동작함수 내에 또다른 함수를 써서 매개변수를 하나 받을 수 있다. 이 변수는 같은 스코프 내에 있는 state값을 먼저 찾는다. 따라서 이를 실행하면 한 번 클릭에 3씩 증가한다. prev 매개변수를 써서 의도한 대로 여러 동작함수를 사용할 수 있다. 물론 매개변수 이름도 마음대로 설정할 수 있다. 더불어 prev에서 같은 스코프 내에 값이 없을 경우 스코프 밖에 있는 stater값을 찾는다. 

 

Props

props는 하위 컴포넌트로 값을 넘기는 것을 뜻한다. 아래 코드를 메인 페이지다. 여기에 ExamplePage를 import했다. 그리고 qqq 변수에 "다람쥐초"라는 문자열을 넣었다.

import ExamplePage from "../../src/components/units/13-props-children";

export default function PropsChildrenPage() {
  return <ExamplePage qqq="다람쥐초" />;
}

ExamplePage에서 props를 매개변수를 받았고, return에 props.qqq를 썼다.

export default function ExamplePage(props) {
  return (
    <>
      <div>안녕하세요. 영희입니다.</div>
      <div>{props.qqq}</div>
      <div></div>
      <div>안녕하세요 맹구입니다.</div>
    </>
  );
}

컴포넌트 속성에 변수명을 쓰고 값을 넣어 전달하면, 받는 쪽에서는 관련 값을 객체화해 props로 받는다(물론 이름을 자유롭게 바꿀 수 있다). 따라서 객체 값을 불러오듯 props.qqq로 불러와졌음을 위 이미지로 알 수 있다.

 

props.children

props에는 한가지 기능이 더 있다. 속성이 아닌 밸류 값을 넣어서 전달하고, 받는 쪽에서 이를 활용할 수도 있다. 이를 props.children이라 부른다. 위 코드를 재활용했다. ExamplePage 컴포넌트에 닫는 엘레멘트를 추가하고 input을 넣었다.

import ExamplePage from "../../src/components/units/13-props-children";

export default function PropsChildrenPage() {
  return (
    <ExamplePage qqq="다람쥐초">
      <input type="text" />
    </ExamplePage>
  );
}

그리고 ExamplePage에서 props.children을 출력해본다.

export default function ExamplePage(props) {
  return (
    <>
      <div>안녕하세요. 영희입니다.</div>
      <div>{props.qqq}</div>
      <div>{props.children}</div>
      <div>안녕하세요 맹구입니다.</div>
    </>
  );
}

위와 같이 상위 컴포넌트에서 전달한 input이 정상적으로 브라우징됐다. 이렇듯 props는 속성을 통해서 전달하거나 밸류를 통해서 하위 컴포넌트로 전달할 수 있고, 받는 쪽에서는 props 즉 매개변수를 통해 가져와 활용할 수 있다.

 

마무리

state와 props는 컴포넌트 단위로 웹을 제작하는 리액트 특성상 기본 중에 기본인 듯하다. 리액트 사용하면서 state가 없었던 적, props가 없었던 적이 없다. 그만큼 값을 저장하고, 전달하는게 많다. 심지어 setState조차도 props로 넘겨서 하위 컴포넌트에서 작동시킬 정도다. state는 추후 상태관리 라이브러리로 교체해 쓰기도 하지만, props는 오히려 더많은 곳에서 사용한다. 레이아웃을 나눌 때도, 특정라이브러리의 관리 페이지를 분리할 때도 props로 파일을 쪼갠다.

state와 props 사용법을 정리하면서 느낀건 하나다. 이 두가지는 리액트에서 물과 같은 존재다. 어렵지는 않지만, 잘 활용하지 못하면 한 없이 코드가 복잡해질 수 있는 그런 존재. 물 마시는게 어렵진 않지만, 부족하거나 너무 많아도 몸에 이상을 일으키는 점에서 매우 비슷하다.

※ 잘못된 내용이 있을 경우 댓글로 알려주세요. 배우고 익히고 수정하겠습니다:)

'FE > React' 카테고리의 다른 글

state Lifting  (0) 2022.09.26
Container-Presenter  (0) 2022.09.21
static routing & dynamic routing  (0) 2022.09.19
Conditional-rendering  (0) 2022.09.12
JSX?  (0) 2022.08.30