Post

react - Activity 컴포넌트를 활용해보자!

🍊 새로운 컴포넌트 Activity

react 19에서 실험적으로 도입되었다가 정식 컴포넌트로 승격한 <Activity> 컴포넌트에 대해서 알아보자.

현재 회사에서 사용하고있는 react 버전에서는 지원하지 않는 내용이라 실무에서 사용하려면 시간이 좀 더 필요하겠지만, 유용한 기능이기에 개인 작업에서는 종종 사용할 듯 하다.

🍓 Activity 컴포넌트의 역할

Activity 컴포넌트는 아래의 상황에서 유용하게 사용할 수 있다.

  • 숨겨진 컴포넌트의 상태 복원하기
  • 숨겨진 컴포넌트의 DOM 복원하기
  • 표시될 가능성이 있는 콘텐츠 사전 렌더링하기
  • 페이지 로드 중 상호작용 속도 높이기

사용 방식은 다음과 같다.

1
2
3
<Activity mode={isShowingSidebar ? "visible" : "hidden"}>
  <Sidebar />
</Activity>
  • {children}: 해당 예제에서는 <Sidebar>로, 표시하거나 숨길 UI다.
  • mode: visible, hidden 중 하나의 문자열 값으로, 기본값은 visible이다.

💖 숨겨진 컴포넌트의 상태 복원하기

예를 들어 사용자가 사이드 바를 열고 닫을 수 있는 UI를 생각해보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import { useState } from "react"
import Sidebar from "./Sidebar.js"

export default function App() {
  const [isShowingSidebar, setIsShowingSidebar] = useState(true)

  return (
    <>
      {isShowingSidebar && <Sidebar />}

      <main>
        <button onClick={() => setIsShowingSidebar(!isShowingSidebar)}>
          Toggle sidebar
        </button>
        <h1>Main content</h1>
      </main>
    </>
  )
}
  1. 사이드 바 오픈
  2. 특정 서비스(A) 버튼 클릭
  3. 특정 서비스(A) 내부에서 제공하는 서비스 (a, b, c) 가 표시

이 경우 사용자는 총 3번의 클릭을 통해 특정 서비스(A)에서 제공하는 서비스 (a, b, c)를 확인하였다.

그런데 만약 사용자가 다시 사이드 바를 닫은 후에 열면 UI는 어떻게 될까? 위의 예제에서 조건부 렌더링 {isShowingSidebar && <Sidebar />} 처럼 아예 제거(unmount)해버리면 컴포넌트가 다시 만들어져 이전 내부 state가 초기화된다.

즉, 3번은 지워지고, 다시 2번, 3번을 반복해야 (a, b, c)를 확인할 수 있을 것이다.

하지만 <Activity> 컴포넌트를 사용하면 사용자가 사이드바를 열고 닫을 때도 3번 상태를 유지할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import { Activity, useState } from "react"

import Sidebar from "./Sidebar.js"

export default function App() {
  const [isShowingSidebar, setIsShowingSidebar] = useState(true)

  return (
    <>
      <Activity mode={isShowingSidebar ? "visible" : "hidden"}>
        <Sidebar />
      </Activity>

      <main>
        <button onClick={() => setIsShowingSidebar(!isShowingSidebar)}>
          Toggle sidebar
        </button>
        <h1>Main content</h1>
      </main>
    </>
  )
}

💖 숨격진 컴포넌트 DOM 복원하기

해당 예제도 정~말 유용한 예제다!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import { useState } from "react"
import TabButton from "./TabButton.js"
import Home from "./Home.js"
import Contact from "./Contact.js"

export default function App() {
  const [activeTab, setActiveTab] = useState("contact")

  return (
    <>
      <TabButton
        isActive={activeTab === "home"}
        onClick={() => setActiveTab("home")}
      >
        Home
      </TabButton>
      <TabButton
        isActive={activeTab === "contact"}
        onClick={() => setActiveTab("contact")}
      >
        Contact
      </TabButton>

      <hr />

      {activeTab === "home" && <Home />}
      {activeTab === "contact" && <Contact />}
    </>
  )
}

먼저 다음과 같은 컴포넌트 예제가 있다고 해보자. contract에는 textarea가 존재하여, 사용자의 입력을 받게 된다. 그런데 만약 사용자가 textarea에 입력을 해놓고 home 탭으로 돌아가면 어떻게 될까?

지금까지 입력해놓았던 모든 내용이 사라지게 된다.😨

이런 불편함도 <Activity> 컴포넌트를 활용하면 쉽게 해결할 수 있다!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import { Activity, useState } from "react"
import TabButton from "./TabButton.js"
import Home from "./Home.js"
import Contact from "./Contact.js"

export default function App() {
  const [activeTab, setActiveTab] = useState("contact")

  return (
    <>
      <TabButton
        isActive={activeTab === "home"}
        onClick={() => setActiveTab("home")}
      >
        Home
      </TabButton>
      <TabButton
        isActive={activeTab === "contact"}
        onClick={() => setActiveTab("contact")}
      >
        Contact
      </TabButton>

      <hr />

      <Activity mode={activeTab === "home" ? "visible" : "hidden"}>
        <Home />
      </Activity>
      <Activity mode={activeTab === "contact" ? "visible" : "hidden"}>
        <Contact />
      </Activity>
    </>
  )
}

사용 방식은 위에서 살펴본 것과 동일하게, <Activity>로 감싸 mode를 바꿔주기만 하면 된다. 이제 textarea에 내용을 작성하고 탭을 바꾸더라도 이미 작성한 내용은 그대로 남아있게 된다!

예전 프로젝트에서도 탭을 이용해 폼을 나눈 적이 있었는데, 탭을 바꿀 때마다 작성한 내용이 사라져 불편함을 겪은 적이 있었다.. 😇 이제 그러지 않아도 된다니 👍👍

💖 표시될 가능성이 있는 콘텐츠 사전 렌더링하기

1
2
3
4
5
6
{
  activeTab === "home" && <Home />
}
{
  activeTab === "posts" && <Posts />
}

먼저 다음과 같이 tab이 있다고 해보자. activeTab의 기본값이 ‘home’으로 되어있다면 사용자가 처음 접속해서 보는 컴포넌트는 <Home/> 일 것이다. 이 경우 <Posts/>는 렌더링이 되지 않고 있다가, 탭을 눌러야 마운트가 되어 로딩 대기가 발생한다.

만약 <Posts/>가 렌더링에 시간이 오래걸리는 컴포넌트라면 미리 렌더링 하면 사용자의 UX 개선에 도움을 줄 수 있을텐데, 이 때도 <Activity/>를 사용할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import { Activity, useState, Suspense } from "react"
import TabButton from "./TabButton.js"
import Home from "./Home.js"
import Posts from "./Posts.js"

export default function App() {
  const [activeTab, setActiveTab] = useState("home")

  return (
    <>
      <TabButton
        isActive={activeTab === "home"}
        onClick={() => setActiveTab("home")}
      >
        Home
      </TabButton>
      <TabButton
        isActive={activeTab === "posts"}
        onClick={() => setActiveTab("posts")}
      >
        Posts
      </TabButton>

      <hr />

      <Suspense fallback={<h1>🌀 Loading...</h1>}>
        <Activity mode={activeTab === "home" ? "visible" : "hidden"}>
          <Home />
        </Activity>
        <Activity mode={activeTab === "posts" ? "visible" : "hidden"}>
          <Posts />
        </Activity>
      </Suspense>
    </>
  )
}

다음과 같이 <Activity>를 활용하면 App을 앱이 처음 로드될 때 <Posts/>가 사전 렌더링되어 보이기 전에 데이터를 가져올 수 있다!

🌸마무리

리액트 공식문서를 읽으면서 새로 추가 된 기능들 중에서는 특별한 경우에만 사용할 것들이 종종 있는데, 이 <Activity> 컴포넌트는 실무에서도 react 19 이상의 버전을 쓰면 자주 사용하게 되지 않을까 한다.

그 전에 숙달 되어야 필요한 상황에 바로바로 사용할 수 있을 테니, 개인 작업에서 여러번 써보면서 익숙해져야 겠다.😊

🎁참고 사이트

This post is licensed under CC BY 4.0 by the author.