
<Activity>とは
<Activity>はReact 19.2で追加された条件付きでレンダリングするための新機能です。
以下のように、reactからActivityをimportして、Activityのmodeに 'visible' を渡すと表示、'hidden' を渡すと非表示になります。
※ hidden以外が渡された場合も表示されますが、型エラーになります。
App.tsx
import { Activity } from 'react'
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import './App.css'
function App() {
const currentSeconds = new Date().getSeconds()
const currentMode = currentSeconds % 2 === 0 ? 'visible' : 'hidden'
return (
<>
<h1>Activity</h1>
<Activity mode={currentMode}>
<div>
<a href="https://vite.dev" target="_blank">
<img src={viteLogo} className="logo" alt="Vite logo" />
</a>
<a href="https://react.dev" target="_blank">
<img src={reactLogo} className="logo react" alt="React logo" />
</a>
</div>
</Activity>
<h2>偶数秒ならロゴ表示({currentSeconds})</h2>
<button onClick={() => location.reload()}>ページをリロード</button>
</>
)
}
export default App
一般的に、React 19.1までは {isShow && <Page />} のような形で表示・非表示を行うことが多いです。
しかし、<Activity>で囲んだほうが、表示・非表示の箇所がわかりやすくなり、追加・削除によるGitの差分も明確になるメリットがあります。
TSX
{isShow && <Page />}
TSX
<Activity mode={isShow ? 'visible' : 'hidden'}>
<Page />
</Activity>
<Activity>のmodeは 'visible' または 'hidden' のどちらかしか受け取らないので、複数箇所に使用する場合はgetMode()の関数を使用して、'visible' または 'hidden' を返すようにするとスマートです。
TSX
import { Activity } from 'react'
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import './App.css'
function App() {
const currentSeconds = new Date().getSeconds()
const isEvenSeconds = currentSeconds % 2 === 0
const getMode = (mode: boolean) => mode ? 'visible' : 'hidden'
return (
<>
<h1>Activity</h1>
<Activity mode={getMode(isEvenSeconds)}>
<div>
<a href="https://vite.dev" target="_blank">
<img src={viteLogo} className="logo" alt="Vite logo" />
</a>
<a href="https://react.dev" target="_blank">
<img src={reactLogo} className="logo react" alt="React logo" />
</a>
</div>
</Activity>
<h2>秒が偶数ならロゴ表示({new Date().getSeconds()})</h2>
<button onClick={() => location.reload()}>ページをリロード</button>
</>
)
}
export default App
React 19.1以下で<Activity>を使用する方法
<Activity>は使ってみると便利なので、React 19.1以下のバージョンでも使ってみたいと思う方もいると思います。
React 19.1以下で使いたい場合はActivity.tsxを以下のようなコードで作成して、条件を満たした場合に、children(囲んだコード)を返すようにすれば実装できます。
Activity.tsx
import React, { useState, useEffect, useRef, cloneElement } from 'react'
type RegisterCleanupProp = { __registerCleanup?: (fn: () => void) => void }
export function Activity({
mode,
children,
}: {
mode: 'visible' | 'hidden'
children: React.ReactElement<RegisterCleanupProp>
}) {
const [key, setKey] = useState(0)
const cleanupRef = useRef<(() => void) | null>(null)
useEffect(() => {
if (mode === 'hidden') {
cleanupRef.current?.()
cleanupRef.current = null
} else {
setKey((k) => k + 1)
}
}, [mode])
return (
<div style={{ display: mode === 'visible' ? undefined : 'none' }}>
{cloneElement(children, {
key,
__registerCleanup: (fn: () => void) => {
cleanupRef.current = fn
},
})}
</div>
)
}
App.tsx
import reactLogo from './assets/react.svg'
import viteLogo from '/vite.svg'
import { Activity } from './Activity'
import './App.css'
function App() {
const currentMode = new Date().getSeconds() % 2 === 0 ? 'visible' : 'hidden'
return (
<>
<h1>Activity</h1>
<Activity mode={currentMode}>
<div>
<a href="https://vite.dev" target="_blank">
<img src={viteLogo} className="logo" alt="Vite logo" />
</a>
<a href="https://react.dev" target="_blank">
<img src={reactLogo} className="logo react" alt="React logo" />
</a>
</div>
</Activity>
<h2>秒が偶数ならロゴ表示({new Date().getSeconds()})</h2>
<button onClick={() => location.reload()}>ページをリロード</button>
</>
)
}
export default App