Reactハンズオンラーニング 第2版
posted with ヨメレバ
Alex Banks/Eve Porcello オライリー・ジャパン 2021年08月06日頃
ステート管理
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;