Closed7
[React / TypeScript / Vite] useContextを理解したい
useContext
親から孫へデータを渡す など、Props(引数)で渡していくのがチョット面倒なとき、
ツリーが深くても数行書くだけで簡単にデータを渡すことができるようにするフック
材料
- createContext
- useContext
おさらい
- フックは関数の中の一番外で呼び出す
- もちろんカスタムフックを作ったならば、カスタムフックも関数の中の一番外で呼び出す
固定値など変化しない値を送りたいとき
ベーシックな使い方
単純にコンテキストを作って(createContext)、受けたい人が勝手に受けておく(useContext)だけ。
親.tsx
import Kodomo from "子"
export const ContextTest = createContext("a"); // ここで送りたいデータを作成
export default function Oya() {
~略~
return(
<Kodomo />
);
}
子.tsx(なんもしない)
import Mago from "孫"
export default function Kodomo() {
~略~
return(
<Mago />
);
}
孫.tsx
import ContextTest from "親"
export default function Mago() {
const ababa = useContext(ContextTest); // ここでデータを受けとる
~略~
return(
<div>{ababa}</div>
);
}
useStateをつかって可変な値を送りたいとき
親の送り方だけが変わる
子や孫はベーシックなものと同じ方法で問題ない
送りたいデータ.tsx
import { useEffect, useState } from "react";
export default function useOkuru() {
const [send, setSend] = useState("");
const makeSend = () => {
useEffect(() => {
// なんか更新する処理
const tekitou = "a";
setSend(tekitou);
}, []);
}
return { send, makeSend };
}
みたいなかんじのデータ send を送りたいとする
親.tsx
import { createContext } from "react";
import useOkuru from "送りたいデータ";
import Kodomo from "子"
// ここでまずコンテキストを作っておく
export const ContextTest = createContext<型 | undefined>(undefined);
export default function Oya() {
{ send, makeSend } = useOkuru();
makeSend();
return(
<ContextTest.Provider value={send}> // Providerで囲む。送りたいデータはvalue={}
<Kodomo />
</ContextTest.Provider>
);
}
はまったこと
下記エラーがでた
Uncaught Error: Module "vm" has been externalized for browser compatibility. Cannot access "vm.createContext" in client code. See https://vitejs.dev/guide/troubleshooting.html#module-externalized-for-browser-compatibility for more details.
at Object.get (__vite-browser-external:vm:3:11)
これはViteのエラーで、「vm.createContext」なんて入れてねえから使えねえよ!!!!!と怒られています。
vm モジュールはNode.jsのモジュールなので、
・
・
・
ん???createContextってReactからimportするんだよね…?あれ???
と思って、import 欄を見てみたら、
import { createContext } from "react";
ではなくて
import { createContext } from "vm";
が入ってました。そりゃ怒られる。VSCodeの予測変換も一番上が正しいとは限らないから気をつけようね(自戒)
データの更新もしたいばあい
useStateで、任意のタイミングでsetもしていく場合、更新する関数も一緒にProviderで渡す必要がある
(関数渡さずに値だけ渡すと、確かに更新関数は走るんだけど親目線値が更新されないw(すごく悩んだ))
送りたいデータ.tsx
import { useEffect, useState } from "react";
export default function useOkuru() {
const [send, setSend] = useState("");
const makeSend = (tekitou: string) => {
setSend(tekitou);
}
return { send, makeSend };
}
親.tsx
import { createContext } from "react";
import useOkuru from "送りたいデータ";
import Kodomo from "子"
// ここでまずコンテキストを作っておく
export const ContextTest = createContext<型 | undefined>(undefined);
export default function Oya() {
{ send, makeSend } = useOkuru();
return(
<ContextTest.Provider value={{ send, makeSend }}> // makeSend関数もvalueにぶちこむ
<Kodomo />
</ContextTest.Provider>
);
}
makeSendを使いたい場合も、useContextで拾う
import ContextTest from "親"
export default function Mago() {
const makeSend = useContext(ContextTest).makeSend ;
~略~
return(
<なんかボタンとか onClick={() => makeSend("kousin")} />
);
}
Contextは本当に全画面で使いそうなもの以外はいれないほうがよさそう
- スコープでかい
- いわゆる超グローバル変数みたいなもの
- つまり乱用するとあぶない
- グローバル変数たくさんあるとつらい
用法容量まもろうね
このスクラップは2024/03/01にクローズされました