Yanonoblog!

こつこつと

useDispatch、Providerの役割

はじめに

Reduxの公式ドキュメントに沿って概要を押さえつつ、気になった部分を深掘って整理しています。

本記事では 、Reduxのサンプルアプリを通してuseDispatch、Providerの役割についてまとめていきます。

useDispatch

ストアにアクセスせずにアクションをディスパッチすることができます。

Reduxストアがある場合、アクションクリエーターを用いてアクションをディスパッチできます。

(アクションクリエーターとは、アクションオブジェクトを生成して返す関数のことを指します。)

store.dispatch(increment())

ストア自体に直接アクセスできない場合でも、ディスパッチメソッドにアクセスしたいケースもあります。

その様の場合には、useDispatchを使用します。

import React from 'react';
import { useDispatch } from 'react-redux';
import { increment } from './actions';

function Counter() {
  const dispatch = useDispatch();

  return (
    <button onClick={() => dispatch(increment())}>
      カウントアップ
    </button>
  );
}

export default Counter;

useDispatchフックを使用すると、コンポーネント内部で直接dispatch関数にアクセスすることができます。

したがってボタンがクリックされたときに、incrementアクションクリエーターが呼び出され、その結果生成されたアクションがdispatchされます。

Reduxストアで管理するべき状態

アプリのすべての状態を常にReduxストアに入れる必要はありません。

アプリ全体で必要とされるグローバルな状態はReduxストアに入れるべきです。

ただし、一部の場所でしか必要とされない状態はコンポーネントの状態として保持すべきです。

下記はカウンターに加算する数値を調整するテキストフォームの実装例です。

// features/counter/Counter.js

const [incrementAmount, setIncrementAmount] = useState('2')

return (
  <div>
    <input
      value={incrementAmount}
      onChange={e => setIncrementAmount(e.target.value)}
    />
    <button
      onClick={() => dispatch(incrementByAmount(Number(incrementAmount) || 0))}
    >
      Add Amount
    </button>
    <button
      onClick={() => dispatch(incrementAsync(Number(incrementAmount) || 0))}
    >
      Add Async
    </button>
  </div>
)

上記で扱っている数値を表す文字列は、inputのonChangeハンドラでアクションをディスパッチし、リデューサーで保持することでReduxストアに保存することが可能ですが、使用されるのはコンポーネント内部だけですので、useStateフックで保持することが理にかなっています。

React + Reduxアプリでは、グローバルな状態はReduxストアに、ローカルな状態はReactコンポーネントに保持すべきです。

StoreのProvider

ReactコンポーネントがどのようにReduxのストアと通信して

useSelectorやuseDispatchフックがどのようにストアにアクセスするのかについて解説します。

コンポーネント

useSelectorやuseDispatchのフックは<Provider>コンポーネントを通じて特定のReduxストアを見つけます。

下記は、アプリケーションのエントリーポイントであるindex.jsファイルのコードです。

// src/index.js

import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'
import store from './app/store'
import { Provider } from 'react-redux'
import * as serviceWorker from './serviceWorker'

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
)

Reactでは、renderメソッドを使ってルートとなるコンポーネントレンダリングする必要があります。

useSelectorやuseDispatchといったフックが適切に機能するためには、コンポーネントを使ってReduxストアをReactのコンポーネントツリーに提供する必要があります。

ストアは下記の通りapp/store.jsで作成しているので、src/index.jsでインポートします。

// src/app/store.js

import { configureStore } from '@reduxjs/toolkit';
import counterReducer from '../features/counter/counterSlice';

export const store = configureStore({
  reducer: {
    counter: counterReducer,
  },
});

そして、アプリケーション全体をコンポーネントで囲み、storeプロパティとしてストアを渡します。

<Provider store={store}>

このように設定することで、useSelectorやuseDispatchフックを使う全てのReactコンポーネントが、に渡されたReduxストアと通信することが可能になります。

これがReactとReduxの橋渡しを行うコンポーネントの役割となります。

参考

続く…

コメント

本記事の内容は以上になります!

書籍の続きのアウトプットも随時更新したいと思います。


プログラミングスクールのご紹介 (卒業生より)

お世話になったプログラミングスクールであるRUNTEQです♪

https://runteq.jp/r/ohtFwbjW

こちらのリンクを経由すると1万円引きになります。

RUNTEQを通じて開発学習の末、受託開発企業をご紹介いただき、現在も双方とご縁があります。

もし、興味がありましたらお気軽にコメントか、TwitterのDMでお声掛けください。

https://twitter.com/outputky