#HooksとContext APIでGlobal stateを管理する
Reacttでの状態管理といえばReduxで、Global stateの管理のために長年一緒に使われてきました。 Hooksが実装されてからは、小規模なアプリなどの開発においてはReduxを使わずにHooksとContext APIを使ってGlobal stateを管理する方法がより望ましいのではと思うので、そちらについて書いていきます。
####1.Data Store(contextAPI(createContext))の作成
// src/contexts/AppContext.js
import { createContext } from 'react'
const AppContext = createContext()
export default AppContext
####2.Context ProviderでComponentを囲う&DataStoreの作成(initial state, reducer)
データを提供する側(provider)=親
使いたい側(consumer)=子 という認識。
Context.Providerで囲まれた中にあるconsumerは、providerのデータを使うことができるようになるという仕組み。
*更新処理関数のreducerの処理は別ファイルで記載のため、割愛。
// src/components/App.js
import React, { useEffect, useReducer } from 'react'
import EventForm from './EventForm'
import Events from './Events'
import OperationLogs from './OperationLogs'
import AppContext from '../contexts/AppContext.js'
import reducer from '../reducers'
const App = () => {
const initialState = { //初期値を設定
events: [],
operationLogs: []
}
const [state, dispatch] = useReducer(reducer, initialState)
return (
<AppContext.Provider value={{ state, dispatch }}>
<EventForm />
<Events />
<OperationLogs />
</AppContext.Provider>
)
}
export default App
####3.stateを参照したいcomponent内でuseContextを使う
関数の引数にstateを渡すのではなく、useContextを使って渡してあげることで、そのcomponentに必要な状態やオブジェクトだけを渡すことができるようになる。
// src/components/Events.js
import React, { useContext } from 'react'
import Event from './Event'
import AppContext from '../contexts/AppContext.js'
const Events = () => { //引数ではなるべく値を渡さない
const { state } = useContext(AppContext)
return (
<>
<h4>イベント一覧</h4>
<table>
<thead>
<tr>
<th>ID</th>
<th>タイトル</th>
<th>ボディー</th>
<th></th>
</tr>
</thead>
<tbody>
{ state.events.map((event, index) => (<Event key={index} event={event} />))}
</tbody>
</table>
</>
)
} //dispatchで渡ってくるデータをmapで一覧表示。mapにはkeyが必須(そうすることでuniqueなidが振られたデータを一つずつ表示する)
//propを使ってeventは渡す
//indexのところはもちろんevent.idでもいいが、標準の機能に則ってindexとした方がバグが起きない
export default Events
####孫コンポーネントでもstateやdispatchが使えるようになる
useContextによって、コンポーネントがどれだけ複雑な階層を持っていたとしても、どこでも状態やオブジェクトを参照できるようになる。(これが最大のメリットかと。)
// src/components/Event.js
import React, { useContext } from 'react'
import {
ADD_OPERATION_LOG,
DELETE_EVENT
} from '../actions'
import AppContext from '../contexts/AppContext.js'
import { timeCurrentIso8601 } from '../utils'
const Event = ({ event }) => {
const { dispatch } = useContext(AppContext)
const id = event.id
const handleClickDeleteButton = () => {
const result = window.confirm(`イベント(id=${id})を本当に削除しても良いですか?`)
if (result) {
dispatch({ type: DELETE_EVENT, id }) //Storeの更新にはdispatchを使用
dispatch({
type: ADD_OPERATION_LOG,
description: `イベント(id=${id})を削除しました。`,
operatedAt: timeCurrentIso8601()
})
}
}
return (
<tr>
<td>{id}</td>
<td>{event.title}</td>
<td>{event.body}</td>
<td><button type="button" onClick={handleClickDeleteButton}>削除</button></td>
</tr>
)
}
export default Event
参考:
https://eight-bites.blog/2021/11/global-state-with-hooks/
https://www.udemy.com/course/youtube-react-hooks-css-module/learn/lecture/19962412#overview