useContextとRecoilの違いについて噛み砕いてまとめる

React

React勉強中のびきニキです🐺 今回はふっけ師匠 (@fukke0906) にuseContextとRecoilの違いについて教わったので、備忘録を残しておきたいと思います!

【useContextとRecoilってなに?】 この2つに共通しているのは”グローバルで状態管理ができる”という点です。 component間で楽に値を共有したりできます。 ざっくり言うと「状態をページ間を超えて保持することができる」というもの。 (ここでいう状態とは、”ボタンを押したか / ログインしているかどうか” などを指します)

それじゃあこの2つにはどんな違いがあるのでしょうか。 まとめていきます!

▼ 文章で知る2つの違い

useContext とは Reactが持つContextという機能をシンプルに使えるようにしたReactHooksのひとつ。 React純正なのでめちゃくちゃ安心で、日本語の記事が多いところが魅力です! また、ログイン状態の保持など「複雑な処理」をさせるのに向いています。

Recoil とは Facebookによって作られた状態管理ライブラリのひとつ。 Facebookが提唱したことでいろんなところで使われているんですが、まだβ版なのでなにかあっても自己責任です...。 useContextに比べてより簡単に、短く書けるのが魅力です! しかし、複雑なことをさせようとすると大変なので メニューが開いているか否かなどの「True,Falseの処理」を書くのに向いています。

▼ コードで見る2つの違い

まず2つのファイルを作成します!

src/App.tsx
import React from "react"; export default function App() { return ( <div className="App"> </div> ); }
src/index.tsx
import { StrictMode } from "react"; import { createRoot } from "react-dom/client"; import App from "./App"; const rootElement = document.getElementById("root"); const root = createRoot(rootElement); root.render( <StrictMode> <App /> </StrictMode> );

【useContextの使い方】

今回はuseContextで簡単なカウンターを作ってみます。 以下の新規ファイルを用意してください🦔

src/useContext.tsx
// 必要なデータを引っ張ってくる import React, { createContext, ReactNode, Dispatch, SetStateAction, useState, useEffect } from "react"; // ContextPropsの型をつける type ContextProps = { count: Number; setCount: Dispatch<SetStateAction<Number>>; }; // 共有するデータを作成 export const CounterContext = createContext<ContextProps>({ count: 0, setCount: () => {} }); // Propsにも型をつける type Props = { children: ReactNode; }; // データを配布してみる! export const CounterProvider = ({ children }: Props) => { const [count, setCount] = useState<number>(0); useEffect(() => {}, []); return ( <CounterContext.Provider value={{ count, setCount }}> {children} </CounterContext.Provider> ); };
src/CounterA.tsx
// 必要なデータを引っ張ってくる import { useContext } from "react"; import { CounterContext } from "./useContext"; // カウンターの中身をつくる export const CounterA = () => { const { count, setCount } = useContext(CounterContext); return ( <div> <button onClick={() => setCount((prevState) => prevState + 1)}> A </button> <br /> {count} </div> ); };

ここまで記述したら、実際にuseContextをつかってみましょう!

src/App.tsx
import React from "react"; // 新しくインポート import { CounterA } from "./CounterA"; import { CounterProvider } from "./useContext"; export default function App() { return ( <div className="App"> <b>useContext</b> <CounterProvider> <CounterA /> </CounterProvider> </div> ); }

実際にこのようなカウンターを表示させることが出来ました💯 image

ここで重要なのは、CounterProviderタグで囲った中でだけカウンターが使用できるという点です。 実際に<Counter />をCounterProviderタグの外に配置するとカウンターが機能しなくなります…。 image

useContextを使用する際は必ずProviderタグで囲む! しっかり覚えておきましょう🌸

冒頭でグローバルに状態管理ができる!と記述したので、本当に管理が出来ているかもちゃんと確認してみます 新しくCounterB.tsxを作成して、App.tsxもそれに応じてちょっと追記。

src/CounterB.tsx
import { useContext } from "react"; import { CounterContext } from "./useContext"; export const CounterB = () => { const { count, setCount } = useContext(CounterContext); return ( <div> <button onClick={() => setCount((prevState) => prevState + 1)}> B </button> <br /> {count} </div> ); };
src/App.tsx
import React from "react"; import { Counter } from "./Counter"; import { CounterB } from "./CounterB"; import { CounterProvider } from "./useContext"; export default function App() { return ( <div className="App" <CounterProvider> <CounterA /> <CounterB /> </CounterProvider> </div> ); }

確認してみると、数値が一緒に更新されていくことがわかります!すごい! image


【Recoilの使い方】

Recoilは複雑なことがちょっと苦手なので今回はトグルリストを作ってみましょう! Recoilを使ったことがない人は$npm install recoil $yarn add recoilでインストールしておこうね。 それでは、以下の新規ファイルを用意してください🦔

src/Recoil.tsx
import React from "react"; // Recoilを使うときに必須 import { atom } from "recoil"; // 共有するデータの作成 export const toggleState = atom({ key: "toggleState", default: "false" });

うむ、RecoilはuseStateと比べてスッキリと書くことができるね…

src/ToggleA.tsx
import React from"react" import { useRecoilState } from "recoil"; import { toggleState } from "./recoil" export const ToggleA = () =>{ const[isOpen,setToggle] = useRecoilState(toggleState); return( <div> {isOpen.toString()} <button onClick={()=>setToggle(prevState => !prevState)}/>A</button> </div> ) }

ここまで記述したら、実際にRecoilもつかってみましょう!

src/App.tsx
import React from "react"; import { RecoilRoot } from "recoil"; import { ToggleA } from "./ToggleA"; export default function App() { return ( <div className="App"> <b>Recoil</b> <br /> <RecoilRoot> <ToggleA /> </RecoilRoot> </div> ); }

image

いい感じですね~…! useContextと違い、Recoilを使うときは RecoilRoot というタグで囲みます! これもしっかり覚えておきましょう!

それではこちらもちゃんと状態管理ができているのか、確認してみましょう!
同じ要領でToggleB.tsxを作成して、App.tsx<ToggleB />を書き加えてください。

src/ToggleB.tsx
import React from "react"; import { useRecoilState } from "recoil"; import { toggleState } from "./recoil"; export const ToggleB = () => { const [isOpen, setToggle] = useRecoilState(toggleState); return ( <> {isOpen.toString()} <button onClick={() => setToggle((prevState) => !prevState)}>B</button> </> ); };
src/App.tsx
import React from "react"; import { RecoilRoot } from "recoil"; import { ToggleA } from "./ToggleA"; export default function App() { return ( <div className="App"> <b>Recoil</b> <br /> <RecoilRoot> <ToggleA /> <br /> <ToggleB /> </RecoilRoot> </div> ); }

image

こちらもしっかりと状態が管理されていることがわかります!すごい!

…というわけで、今回は useContextとRecoilの違いについて、噛み砕いてまとめてみました! これであなたもuseContextとRecoilの違いについて完全に理解しましたね✨

以上、Reactを完全に理解したいびきニキがお送りしました🐺 良い状態管理ライフをお送りください!

びきニキ

@BkNkbot

目次