5. State로 리렌더링하기

2024. 6. 10. 16:57리액트 (React)/리액트 레시피 (React Recipt)

5장부터는 UI가 개선되었습니다.

모든 예제 소스는 github repository 에서 확인할 수 있습니다.

 


State

 

사용자 입력을 받거나, 이미지를 교체하는 등 어떤 상태를 저장하고 이를 통해 표현할 일이 생깁니다.

이때 state를 사용하면 됩니다.

 

예를 들어 아래처럼 메시지를 누르면 숨길 수 있고, 아니면 원상 복귀되도록 만든다고 하면

다음과 같이 useState를 통해 state 변수를 만들어서 조건부 렌더링을 만들면 됩니다.

import { useState } from "react";
import "./Message.scss";

export default function Message(...) {
    const [hidden, setHidden] = useState<boolean>(false);

    return (
        <div
            className={`message-box ${isOutgoing ? "out" : "in"}`}
            onClick={() => setHidden(!hidden)}
        >
            <span className="message-line">
                {hidden ? <i className="fa-solid fa-lock" /> : message}
            </span>
            {checked && <i className="fa-solid fa-check" />}
        </div>
    );
}

 

예제 코드를 설명해보면, 먼저 state는 useState 훅(hook)을 통해 만들 수 있습니다.

이때 두 개 변수를 만들 수 있는데, 전자는 상태 변수이고 후자는 set 함수입니다.

const [hidden, setHidden] = useState<boolean>(false);

 

set 함수는 위 예시에서 div 태그를 누르면 본래 hidden 값의 반대가 되도록 사용했습니다.

<div ... onClick={() => setHidden(!hidden)}>

 

 

 

 

 

 


Rendering

 

state가 가지는 가장 중요한 역할은 바로 리렌더링(re-rendering)입니다.

여기서 렌더링이란 우리가 열심히 만든 컴포넌트들을 어떻게 화면에 보여줄 지 구성하는 것입니다.

 

state의 값이 변경되면, 다시 렌더링을 시작합니다.

즉, 최초에는 루트 컴포넌트(root component)부터 시작해서 연결되어있는 모든 컴포넌트를 렌더링하지만,

이후부터는 해당 state가 변경된 컴포넌트를 다시 렌더링 합니다.

 

 

더 자세히 설명해보면, 먼저 리액트는 컴포넌트들을 트리(tree) 구조로 생각하고 있습니다.

 

최초에는 App부터 Message까지 모든 컴포넌트들을 렌더링합니다.

 

이후 만약에 두 번째 Message의 hidden state를 변경해주면 해당 컴포넌트만 다시 렌더링되는 것입니다.

 

그렇다면 Screen의 하위 컴포넌트들은 건드리지 않고, 내부 태그값만 바꾸는 건 어떨까요?

특정 ms 초마다 콜백 함수를 호출하는 기능을 가진 setInterval 함수로 상태값을 1초마다 바꿔보도록 합니다.

import { ReactNode, useState } from "react";
import "./Screen.scss";

export default function Screen({ children }: { children: ReactNode }) {
    const [currentText, setCurrentText] = useState<string>(new Date().toTimeString());

    setInterval(() => setCurrentText(new Date().toTimeString()), 1000);

    return (
        <div className="screen">
            {children}
            <div>{currentText}</div>
        </div>
    );
}

 

이때는 오직 Screen만 다시 렌더링하게 됩니다.

 

 

만일 여기서 input을 놓으면 어떻게 될까요?

Screen이 다시 렌더링 되었으니, input에 작성했던 텍스트가 1초마다 사라질까요?

import { ReactNode, useState } from "react";
import "./Screen.scss";

export default function Screen({ children }: { children: ReactNode }) {
    ...
    
    return (
        <div className="screen">
            {children}
            <div>{currentText}</div>
            <input />
        </div>
    );
}

 

아닙니다. 오직 시간 div만 변경되는 걸 확인할 수 있습니다.

 

이는 컴포넌트를 리렌더링해서 나온 결과를 이전 DOM 노드들과 비교하여 다른 부분만 수정하기 때문입니다.

 

즉 요약하면 최초 렌더링 이후 특정 컴포넌트의 state가 변경되면,

  1. 해당 컴포넌트를 찾는다
  2. 해당 컴포넌트만 다시 렌더링한다.
  3. 렌더링 결과를 이전 DOM 노드들과 비교해서 다른 부분만 수정한다.

를 수행합니다.

 

 

 

 

 

 

 


References

 

 

State: A Component's Memory – React

The library for web and native user interfaces

react.dev

 

 

Render and Commit – React

The library for web and native user interfaces

react.dev

 

'리액트 (React) > 리액트 레시피 (React Recipt)' 카테고리의 다른 글

7. State 보존하기  (0) 2024.06.11
6. 인터렉티브한 Input 만들기  (0) 2024.06.10
4. CSS 입히기  (0) 2024.06.10
3. 조건부 렌더링 사용하기  (0) 2024.06.09
2. Props 전달하기  (0) 2024.06.09