「Reactハンズオンラーニング」の感想・備忘録2

スポンサーリンク
「Reactハンズオンラーニング」の感想・備忘録1の続き

ステート管理

6.3.3 カスタムフック

例えば、以下のテキストボックスの記述は重複してしまう。

<input type="text" value={msg1} onChange={e=>setMsg1(e.target.value)}/>
<input type="text" value={msg2} onChange={e=>setMsg2(e.target.value)}/>

カスタムフックを使えば、重複したコードを切り出すことができる。
以下の例は、初期値を受け取り配列を返すフックである。
(配列の先頭要素はvalueとonChangeを持つオブジェクト、2番目はリセットするための関数)

import {useState} from 'react'

export const useInput = initialValue => {
  const [value, setValue] = useState(initialValue)
  return [
    {value, onChange: e=>setValue(e.target.value)},
    () => setValue(initialValue)
  ]
}

上記フックは以下のように使用する。

import {useInput} from './hooks'

function Form({handelSubmit}) {
  const [msg1Props, resetMsg1] = useInput("")
  const [msg2Props, resetMsg2] = useInput("")
  const submit = e => {
    e.preventDefault()
    handelSubmit(msg1Props.value, msg2Props.value);
    resetMsg1()
    resetMsg2()
  }
  return (
    <form onSubmit={submit}>
      <p><input {...msg1Props}/></p>
      <p><input {...msg2Props}/></p>
      <button>送信</button>
    </form>
  );
}

export default Form;

6.4.3 コンテキストとステートの併用

  • コンテキストで管理されたステートの値を変更するためには、ステートを定義したコンポーネントでProviderコンポーネントをレンダリングする必要がある。
  • これにより、ステートが変更されるとステートを定義したコンポーネントが再描画され、 Provider配下のコンポーネントも再描画される。
  • このようにステートを保持するコンポーネントが Providerコンポーネントを描画する場合、そのコンポーネントはカスタムプロバイダーと呼ばれる。
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import ColorProvider from './ColorProvider';
import App from './App';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <ColorProvider>
      <App/>
    </ColorProvider>
  </React.StrictMode>
);
import {createContext, useState} from 'react'
import App from './App';

export const ColorContext = createContext({})
function ColorProvider({children}) {
  const [color, setColor] = useState("#f00")
  const setBlue = () => setColor("#00f")
  return (
    <ColorContext.Provider value={{color, setColor, setBlue}}>
      {children}
    </ColorContext.Provider>
  );
}
export default ColorProvider
import Form from './Form'

function App() {
  return (
    <Form/>
  );
}
export default App;
import {useContext} from 'react'
import {ColorContext} from './ColorProvider'

function Form() {
  const {color, setColor, setBlue} = useContext(ColorContext)
  return (
    <div>
      <p>color: {color}<button type="button" onClick={e => setColor("#0f0")}>greenに変更</button></p>
      <p><button type="button" onClick={e => setBlue()}>setBlue()</button></p>
    </div>
  );
}
export default Form;

6.4.4 コンテキストとカスタムフックの併用

  • カスタムフックを使うことで、コンシューマーにはコンテキストを隠蔽することができる。
  • これにより、例えばコンポーネントの開発者にコンテキストの知識がなくても、コンテキストデータを簡単に使うことができる。
  • また、ロジックをフックに隠蔽することで、コンポーネントはUIの構築に専念することができる。
  • 以下のように、コンテキストインスタンスではなくuseColorというカスタムフックをexportする。
    たったこれだけの変更で、コンシューマーではuseColorを呼び出すだけでコンテキストの値を取得することができる。
import {createContext, useState, useContext} from 'react'
import App from './App';

const ColorContext = createContext({})
export const useColor = () => useContext(ColorContext)
function ColorProvider() {
  const [color, setColor] = useState("#f00")
  const setBlue = () => setColor("#00f")
  return (
    <ColorContext.Provider value={{color, setColor, setBlue}}>
      <App/>
    </ColorContext.Provider>
  );
}

export default ColorProvider

コンシューマーではuseContext、ColorContextのインポートが不要となり、useColorをインポートするだけとなる。

import {useColor} from './ColorProvider'

function Form({handleSubmit}) {
  const {color, setColor, setBlue} = useColor()
  return (
    <div>
      <p>color: {color}<button type="button" onClick={e => setColor("#0f0")}>greenに変更</button></p>
      <p><button type="button" onClick={e => setBlue()}>setBlue()</button></p>
    </div>
  );
}

export default Form;

コメント