【2024年最新】React ReduxとRedux Toolkitの完全ガイド | Hooksとの連携も解説

当サイトでは一部リンクに広告が含まれています
Reactアイコン

ReactアプリケーションでReduxを使った状態管理に悩んでいませんか?

本記事では、ReactとReduxの基本から、最新のRedux ToolkitやHooksとの連携まで、わかりやすく解説します!

この記事を書いた人
筆者のプロフィールアイコン
  • 現役のフルスタックエンジニアとして活躍中
  • 開発チームリーダーとして複数プロジェクトをリード
  • 副業プログラミングスクール講師として数百名以上を指導してきた教育のプロ
  • プログラミングスクールのカリキュラム執筆経験あり
目次

1. ReactとReduxの基本:初心者のための入門ガイド

ReactとReduxは、現代のWebアプリケーション開発において非常に重要な役割を果たしています。

Reactはユーザーインターフェースを構築するためのJavaScriptライブラリであり、Reduxはアプリケーションの状態を管理するためのライブラリです。

Reactの基本

Reactでは、UIを構成する各要素を「コンポーネント」として定義します。以下は簡単なReactコンポーネントの例です:

function Welcome({ name }) {
  return <h1>こんにちは、{name}さん</h1>;
}

ReactDOM.render(
  <Welcome name="山田" />,
  document.getElementById('root')
);

このコードは「こんにちは、山田さん」というメッセージを表示する単純なコンポーネントです。

Reduxの基本

Reduxは、アプリケーションの状態(state)を一元管理するためのライブラリです。以下は、Reduxの基本的な使用例です:

import { createStore } from 'redux'

// Reducer
function counterReducer(state = { value: 0 }, action) {
  switch (action.type) {
    case 'increment':
      return { value: state.value + 1 }
    default:
      return state
  }
}

// Store
let store = createStore(counterReducer)

// State取得
console.log(store.getState())
// { value: 0 }

// Action実行
store.dispatch({ type: 'increment' })

console.log(store.getState())
// { value: 1 }

このコードでは、カウンターの値を管理するシンプルなReduxストアを作成しています。

2. Reduxの必要性:なぜReactアプリにReduxが重要なのか

Reduxは、以下の理由からReactアプリケーションで重要な役割を果たします:

  • グローバルな状態管理:複数のコンポーネントで共有される状態を一元管理できます。
  • 予測可能な状態更新:状態の更新が純粋関数(Reducer)によって行われるため、挙動が予測しやすくなります。
  • デバッグの容易さ:Redux DevToolsを使用することで、状態の変化を簡単に追跡できます。
  • ミドルウェアサポート:非同期処理やロギングなどの機能を簡単に追加できます。

特に大規模なアプリケーションや複雑な状態管理が必要な場合、Reduxの利用は非常に有効です。

3. Redux Toolkitの導入:開発を加速させる最新ツール

Redux Toolkitは、Redux開発を簡素化し、効率化するために作られた公式ツールです。以下の特徴があります:

  • ボイラープレートコードの削減
  • 自動的な不変性の処理
  • デフォルトでのミドルウェア設定

Redux Toolkitを使用した例を見てみましょう:

import { createSlice, configureStore } from '@reduxjs/toolkit'

const counterSlice = createSlice({
  name: 'counter',
  initialState: { value: 0 },
  reducers: {
    increment: state => { state.value += 1 },
    decrement: state => { state.value -= 1 }
  }
})

const store = configureStore({
  reducer: counterSlice.reducer
})

export const { increment, decrement } = counterSlice.actions
export default store

このコードは、従来のReduxに比べてはるかに簡潔になっています。

4. HooksとReduxの連携:useSelector, useDispatchの活用法

React HooksとReduxを組み合わせることで、より簡潔で読みやすいコードを書くことができます。特にuseSelectoruseDispatchは重要です。

import React from 'react'
import { useSelector, useDispatch } from 'react-redux'
import { increment, decrement } from './counterSlice'

function Counter() {
  const count = useSelector(state => state.counter.value)
  const dispatch = useDispatch()

  return (
    <div>
      <span>Count: {count}</span>
      <button onClick={() => dispatch(increment())}>+</button>
      <button onClick={() => dispatch(decrement())}>-</button>
    </div>
  )
}

このコードでは、useSelectorで状態を取得し、useDispatchでアクションをディスパッチしています。

5. TypeScriptとRedux:型安全な状態管理の実現

TypeScriptとReduxを組み合わせることで、型安全性を確保しつつ、より堅牢なアプリケーションを構築できます。

import { createSlice, PayloadAction } from '@reduxjs/toolkit'

interface CounterState {
  value: number
}

const initialState: CounterState = { value: 0 }

const counterSlice = createSlice({
  name: 'counter',
  initialState,
  reducers: {
    increment: (state) => { state.value += 1 },
    addAmount: (state, action: PayloadAction<number>) => {
      state.value += action.payload
    }
  }
})

export const { increment, addAmount } = counterSlice.actions
export default counterSlice.reducer

このコードでは、状態とアクションの型を明示的に定義しています。これにより、型の不一致によるバグを事前に防ぐことができます。

6. パフォーマンス最適化:ReduxとReactの効率的な連携

ReduxとReactを効率的に連携させ、アプリケーションのパフォーマンスを最適化するためのいくつかのテクニックを紹介します。

メモ化の活用

ReactのmemoやReduxのcreateSelectorを使用して、不必要な再レンダリングを防ぎます。

import { createSelector } from '@reduxjs/toolkit'
import { RootState } from './store'

const selectTodos = (state: RootState) => state.todos
const selectFilter = (state: RootState) => state.filter

export const selectFilteredTodos = createSelector(
  [selectTodos, selectFilter], (todos, filter) => {
    switch (filter) {
      case 'completed':
        return todos.filter(todo => todo.completed)
      case 'active':
        return todos.filter(todo => !todo.completed)
      default:
        return todos
    }
  }
)

正規化されたステート構造

データを正規化して保存することで、更新や検索を効率化します。

interface NormalizedState {
  todos: {
    byId: { [id: number]: Todo },
    allIds: number[]
  }
}
const initialState: NormalizedState = {
  todos: {
    byId: {},
    allIds: []
  }
}

バッチ更新の利用

複数の更新を一度にディスパッチすることで、パフォーマンスを向上させます。

import { batch } from 'react-redux'
const handleMultipleUpdates = () => {
  batch(() => {
    dispatch(action1())
    dispatch(action2())
    dispatch(action3())
  })
}

まとめ:効果的なReact Redux活用のポイント

React Reduxを効果的に活用するためのポイントをまとめます:

  • Redux Toolkitを使用して、ボイラープレートコードを削減し、開発効率を上げる
  • Hooksを活用して、よりシンプルで読みやすいコードを書く
  • TypeScriptを導入し、型安全性を確保する
  • パフォーマンス最適化テクニックを適用し、アプリケーションの効率を高める
  • 実践的な例を通じて、理論と実装を結びつける

これらのポイントを押さえることで、React Reduxを使った効果的な状態管理が可能になります。大規模なアプリケーション開発においても、保守性の高い、パフォーマンスの良いコードを書くことができるでしょう。

React Reduxは常に進化しています。最新の動向にも注目しつつ、自身のプロジェクトに最適な方法を選択し、実装していくことが重要です。

React を効率的に身につける勉強法は?

React には興味があっても、プログラミング学習をはじめたばかりであれば、以下のような疑問を持つかもしれません。

  • Reactエンジニアとして活躍するために何をすればいい?
  • 何から勉強すればいいんだろう?
  • 絶対に転職を成功させるには?

React は習得が比較的難しいため、勉強法の選び方を間違うと時間・労力・お金が無駄になってしまいます…。

そのため、こちらの記事を参考に、ご自身に最適な学習方法を選んでみませんか?

目次