1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ReactにおけるGlobal State管理

Last updated at Posted at 2022-02-19

#HooksとContext APIでGlobal stateを管理する

Reacttでの状態管理といえばReduxで、Global stateの管理のために長年一緒に使われてきました。 Hooksが実装されてからは、小規模なアプリなどの開発においてはReduxを使わずにHooksとContext APIを使ってGlobal stateを管理する方法がより望ましいのではと思うので、そちらについて書いていきます。

##Context ProviderとData Store
スクリーンショット 2022-02-19 13.16.49.png

####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

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?