React状態管理ライブラリvaltioを使ってみた
こんにちは。データアナリティクス事業本部 サービスソリューション部の北川です。
最近、valtioの公式サイトができたらしいので、valtioを使った状態管理について書きたいと思います。
valtioとは
valtioとは、Poimandresが開発している状態管理ライブラリの一つになります。
https://valtio.pmnd.rs/docs/introduction/getting-started
valtioは、Reactの外部で状態を管理します。そのため、どこからでも値を変更できるのが特徴です。 記述量が少なく、同じ状態管理ライブラリのRecoil同様、状態をオブジェクトごとに分割して管理することができます。
stateを直接操作するので、破壊的なメソッドを使用できる点も特徴です。上記の通り、Reactの外から操作可能なため、基本的に使うhooksが、stateをReact(コンポーネント)内にとってくるuseSnapshotくらいになります。
valtioを使ってみる
プロジェクトの作成。
npx create-next-app --typescript valtio-app
valtioをインストール。
yarn add valtio // または npm install valtio
状態を管理するファイルを作成
状態を管理するため、stateというフォルダの中にstate.tsを作成します。
今回は、todoを表示する配列を作成します。また、todoを追加する関数も作成します。関数用のファイルを分割しても良いですが、今回はまとめてあります。
オブジェクトをproxyでラップし、状態を管理します。
import { proxy } from "valtio"; export const state = proxy<{ todoList: string[]}>({ todoList: [], }); export const addItem = (item: string) => { if (!item) { return; } state.todoList.push(item); };
stateの表示
React内で状態を表示し、変更します。 valtioでは、useSnapshotを使用して、状態を取得します。 useSnapshotは、プロキシでラッピングされたstateを返すhooksです。
const snap = useSnapshot(state); console.log(snap)
index.tsxを変更します。
import { useState } from "react"; import { useSnapshot } from "valtio"; import styles from "../styles/Home.module.css"; import { addItem, state } from "../state/state"; import { NextPage } from "next"; const Home: NextPage = () => { const snap = useSnapshot(state); const [todo, setTodo] = useState<string>(""); return ( <div className={styles.container}> <h3>TodoList</h3> <input type="text" onChange={(e) => setTodo(e.target.value)} /> <input type="submit" value="追加" onClick={() => addItem(todo)} /> {snap.todoList.map((todo) => { return <p key={todo}>・{todo}</p>; })} </div> ); }; export default Home;
動作確認
yarn dev
フォームに値を入れて追加すると、stateも変更しています。
ページ遷移
また、ページ遷移しても状態が維持されているか確認します。
/pages/about.tsxを作成します。
import { useState } from "react"; import { useSnapshot } from "valtio"; import styles from "../styles/Home.module.css"; import { addItem, state } from "../state/state"; import Link from "next/link"; import { NextPage } from "next"; const About: NextPage = () => { const { todoList } = useSnapshot(state); const [todo, setTodo] = useState<string>(""); return ( <div className={styles.container}> <Link href="/">Index</Link> <h1>About Page</h1> <h3>TodoList</h3> <input type="text" onChange={(e) => setTodo(e.target.value)} /> <input type="submit" value="追加" onClick={() => addItem(todo)} /> {todoList.map((todo) => { return <p key={todo}>・{todo}</p>; })} </div> ); }; export default About;
index.tsxを変更します。
import { useState } from "react"; import { useSnapshot } from "valtio"; import styles from "../styles/Home.module.css"; import Link from "next/link"; import { addItem, state } from "../state/state"; import { NextPage } from "next"; const Home: NextPage = () => { const snap = useSnapshot(state); const [todo, setTodo] = useState<string>(""); return ( <div className={styles.container}> <Link href="/about">About</Link> <h1>Index Page</h1> <h3>TodoList</h3> <input type="text" onChange={(e) => setTodo(e.target.value)} /> <input type="submit" value="追加" onClick={() => addItem(todo)} /> {snap.todoList.map((todo) => { return <p key={todo}>・{todo}</p>; })} </div> ); }; export default Home;
ページを遷移しても、状態が保持されています。
まとめ
簡単にですが、valtioで状態管理を行ってみました。
コンポーネント内は、stateを表示する機能だけを持たせることで、ファイルの役割が明確化し、可読性も上がるのではと思います。 Reactの状態管理ライブラリは種類が多く、どれがベストなのか選択するのが難しいですが、プロジェクトの特徴によって使い分けれるようになりたいですね。
ではまた。