「モダンJavaScriptの基本から始めるReact実践の教科書」の感想・備忘録4

スポンサーリンク
「モダンJavaScriptの基本から始めるReact実践の教科書」の感想・備忘録3の続き

グローバルState

バケツリレーのデメリット

Propsのバケツリレーには以下のデメリットがある。

  • Propsが肥大化する
  • 本来必要のないPropsを受け取るので、再利用できないコンポーネントになってしまう
  • Propsが変更されたら再レンダリングが発生してしまう

ContextでのグローバルState

グローバルStateを管理するライブラリはいくつかあるが、Reactが持っているContext機能を使うことでも実現することができる。

導入手順

  1. React.createContext()でContextの器を作成
    createContext()の引数は{}とする。
    引数は初期値となっているが、値はReact.Context.Providerコンポーネントのvalue属性で渡すので通常は初期値が使われることはない。
    (React.Context.Providerでラップされていないコンポーネントがコンテキストにアクセスしたときに使われる)
  2. 作成したReact.ContextのReact.Context.ProviderコンポーネントでStateを参照したいコンポーネントを囲む
    React.Context.Providerのvalue属性に値を渡す。
  3. Stateを参照したいコンポーネントでReact.useContext()を使う

プロバイダーコンポーネント

Contextを保持するためのプロバイダーコンポーネントを作成すると良い。
プロバイダーコンポーネントは何でも囲めるようにPropsとしてchildrenを受け取るようにするのがポイント。

import { createContext } from 'react';

export const AdminFlagContext = createContext({});
export const AdminFlagProvider = ({children}) => {
  return (
    <AdminFlagContext.Provider value={{name: 'hoge'}}>
      {children}
    </AdminFlagContext.Provider>
  )
}
グローバルStateを参照したいコンポーネントをProviderコンポーネントで囲む
import {AdminFlagProvider} from './components/providers/AdminFlagProvider';
// を追加し、
return (
  <AdminFlagProvider>
    <Oya/>
  </AdminFlagProvider>
);
利用時
import { useContext } from 'react';
import {AdminFlagContext} from './providers/AdminFlagProvider';
//を追加し、
console.log(useContext(AdminFlagContext).name})

ContextにStateを格納する

上記の例では固定値をvalue属性に指定したが、Stateを指定する場合は以下のようになる。

import { createContext, useState } from 'react';

export const AdminFlagContext = createContext({})
export const AdminFlagProvider = ({ children }) => {
  const [isAdmin, setIsAdmin] = useState(false)
  return (
    <AdminFlagContext.Provider value={{ isAdmin, setIsAdmin }}>
      {children}
    </AdminFlagContext.Provider>
  )
}
import { memo, useContext } from 'react';
import {AdminFlagContext} from './providers/AdminFlagProvider';

const Ko = memo(({ resetNum })=>{
  console.log('子')
  const {isAdmin, setIsAdmin} = useContext(AdminFlagContext)
  return (
    <>
      <h1>子: {isAdmin ? '管理者です' : '管理者以外です'}</h1>
      <button onClick={setIsAdmin(!isAdmin)}>切り替え</button>
      <button onClick={resetNum}>resetNum</button>
    </>
    )
})

export default Ko;

コメント