この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
こんにちは。データアナリティクス事業本部 サービスソリューション部の北川です。
最近、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でラップし、状態を管理します。
/state/state.ts
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を変更します。
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を作成します。
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を変更します。
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の状態管理ライブラリは種類が多く、どれがベストなのか選択するのが難しいですが、プロジェクトの特徴によって使い分けれるようになりたいですね。
ではまた。