Reactが初めて登場したとき、開発者はそのUIの状態管理のシンプルさに感動しました。しかしアプリケーションが複雑になるにつれ、コンポーネントの表示・非表示を管理しながら状態やパフォーマンスを維持するのは思ったより難しいことに気付きました。従来はCSSでの非表示切り替えや、コンポーネントを完全にアンマウントする方法に頼っていましたが、どちらにも欠点がありました。
そこでReactチームがこの課題に着目し、新たに実験的な超便利機能 <Activity>
を発表しました!このコンポーネントは表示の切り替えを簡単にしつつ、状態やパフォーマンスも維持できる優れものです。<Activity mode="hidden">
を使うと、Reactはコンポーネントをアンマウントしつつ状態を保存し、バックグラウンドで低い優先度でレンダリングを続けます。一方、<Activity mode="visible">
は通常通りのレンダリングを行います。
よくあるシナリオを考えてみましょう。別のページに移動するとき、以前はユーザーが入力した情報や状態がすべて消えてしまいました。せっかくフォームに入力したのに、一度別ページに行くと戻ったときにはすべてがリセットされる…そんなイライラ、ありますよね?
これまでの典型的なコード例はこうでした:
function App() {
const { url } = useRouter();
return (
<>
{url === '/' && <Home />}
{url !== '/' && <SubPage />}
</>
);
}
残念ながら、この方法では<Home />
から離れるとすぐに状態が失われます。ところが新しい<Activity>
を使えば全てが解決します!
function App() {
const { url } = useRouter();
return (
<>
<Activity mode={url === '/' ? 'visible' : 'hidden'}>
<Home />
</Activity>
{url !== '/' && <SubPage />}
</>
);
}
この変更で、一度ページを離れても入力状態はそのまま保持され、スムーズで直感的なユーザー体験を提供します。
さらにすごいのは、Reactの新機能<Activity>
がユーザーの次の行動を先読みして、事前にコンポーネントをレンダリングしておける点です。例えば、詳細ページに移動する際に通常はデータ取得のため待ち時間が発生しますが、<Activity>
を使うとユーザーがクリックする前に裏でレンダリングし、データを準備しておくことができます。
export default function App() {
const { url } = useRouter();
const pictureId = url.split('/').pop();
const [pictures, setPictures] = useState([]);
useEffect(() => {
async function loadPictures() {
const imgs = await getPictures();
setPictures(imgs);
}
loadPictures();
}, []);
return (
<ViewTransition>
{pictures.map(({id}) => (
<Activity key={id} mode={pictureId === id ? 'visible' : 'hidden'}>
<PictureDetails id={id}/>
</Activity>
))}
<Activity mode={url === '/' ? 'visible' : 'hidden'}>
<Home />
</Activity>
</ViewTransition>
);
}
これにより、ユーザーが画像を選択するときに待ち時間がほぼなくなり、プロ並みの滑らかな体験が実現できます。
さらに将来的には、モーダル表示やバックグラウンドでの更新停止、メモリ管理まで幅広く対応するモードも計画中とのこと。これからのReact開発には欠かせない存在になりそうです。
Reactが提供する新たな<Activity>
を使えば、UI開発はもっと楽しく簡単に、そしてユーザー体験も劇的に向上します。これからのReact開発者必見の機能、ぜひ試してみてください!
※この記事執筆時点では APIは実験的な機能であり、安定版のReactにはまだ含まれていません。試すにはReactパッケージを最新のexperimentalバージョンにアップグレードしてください。