0
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?

Reduxで始めるJavaScript最新状態管理入門

Posted at

1. はじめに:Reduxとは何か

ReduxはJavaScriptアプリケーションにおける「状態管理」を効率化するためのライブラリです。特にReactと組み合わせて使われることが多いですが、React専用ではなく、VueやAngularなど他のフレームワークとも連携できます。Reduxを導入することで、アプリケーション全体の状態(データ)を一元管理し、どこからでも状態の参照や更新が可能になります。これにより、コンポーネント間のデータ共有が容易になり、データフローが明確化され、バグの発生やデバッグの難しさを大きく減らすことができます。

// CDN経由でReduxを利用する例
<script src="https://unpkg.com/redux@latest/dist/redux.min.js"></script>

2. Reduxの3つの基本原則

Reduxには「唯一の情報源(Single Source of Truth)」「状態は読み取り専用(State is Read-Only)」「変更は純粋な関数で(Changes are made with pure functions)」という3つの基本原則があります。全ての状態は一つのストアで管理され、状態の変更は必ずアクションを通して行われます。状態の更新はリデューサーという純粋関数で定義され、副作用を排除し予測可能なアプリケーションを実現します。

// シンプルなReducer
function counter(state = 0, action) {
  switch (action.type) {
    case 'INCREMENT':
      return state + 1
    case 'DECREMENT':
      return state - 1
    default:
      return state
  }
}

3. Reduxの主要コンポーネント:Store, Action, Reducer

Reduxの中心は「Store(状態の保管場所)」「Action(状態変更の命令)」「Reducer(状態をどう変えるかのルール)」の3つです。Storeはアプリ全体の状態を保持し、Actionは何が起きたかを表すオブジェクト、Reducerは現在の状態とActionを受け取り新しい状態を返します。この3つの役割をしっかり理解することがReduxの第一歩です。

const store = Redux.createStore(counter)
store.dispatch({ type: 'INCREMENT' }) // 状態が1増加

4. 最小構成のカウンターアプリ

Reduxの基本を学ぶにはカウンターアプリが最適です。Reducerで状態遷移を定義し、Storeを作成し、Actionをdispatchすることで状態が変化します。UIは素のJavaScriptやReactなどで自由に構築できます。

<!DOCTYPE html>
<html>
<head>
  <script src="https://unpkg.com/redux@latest/dist/redux.min.js"></script>
</head>
<body>
  <div>
    <span id="value">0</span>
    <button id="increment">+1</button>
    <button id="decrement">-1</button>
  </div>
  <script>
    function counter(state = 0, action) {
      switch (action.type) {
        case 'INCREMENT': return state + 1
        case 'DECREMENT': return state - 1
        default: return state
      }
    }
    const store = Redux.createStore(counter)
    const valueEl = document.getElementById('value')
    function render() {
      valueEl.innerHTML = store.getState()
    }
    render()
    store.subscribe(render)
    document.getElementById('increment').onclick = () => store.dispatch({ type: 'INCREMENT' })
    document.getElementById('decrement').onclick = () => store.dispatch({ type: 'DECREMENT' })
  </script>
</body>
</html>

5. ActionとAction Creatorの役割

Actionは状態変更の命令書であり、typeプロパティを必ず持ちます。Action CreatorはActionを生成する関数で、複雑なアクションやパラメータ付きアクションの管理に役立ちます。

function increment() {
  return { type: 'INCREMENT' }
}
function decrement() {
  return { type: 'DECREMENT' }
}
store.dispatch(increment())
store.dispatch(decrement())

6. 複数ReducerとcombineReducers

アプリが大きくなると状態管理も複雑になります。Reduxでは複数のReducerをcombineReducersで合成し、状態を分割して管理できます。これにより、大規模アプリでも見通しの良い設計が可能です。

const rootReducer = Redux.combineReducers({
  counter: counterReducer,
  todos: todosReducer
})
const store = Redux.createStore(rootReducer)

7. Reactとの連携(react-redux)

ReactでReduxを使う場合は、react-reduxパッケージを利用します。Providerでアプリ全体を包み、useSelectorやuseDispatchフックで状態やアクションを簡単に扱えます。

import React from 'react'
import { Provider, useSelector, useDispatch } from 'react-redux'
import store from './store'
function App() {
  const count = useSelector(state => state.count)
  const dispatch = useDispatch()
  return (
    <div>
      <h1>カウント: {count}</h1>
      <button onClick={() => dispatch({ type: 'INCREMENT' })}>+1</button>
      <button onClick={() => dispatch({ type: 'DECREMENT' })}>-1</button>
    </div>
  )
}
// index.jsで
import ReactDOM from 'react-dom'
ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
)

8. Redux Toolkitによる最新開発

Redux Toolkitは、Reduxの公式推奨ツールで、ボイラープレートを減らし、より簡単に安全にReduxを使えるようにします。createSliceやconfigureStoreを使えば、ReducerやActionの自動生成も可能です。

import { configureStore, createSlice } from '@reduxjs/toolkit'
const counterSlice = createSlice({
  name: 'counter',
  initialState: { value: 0 },
  reducers: {
    increment: state => { state.value += 1 },
    decrement: state => { state.value -= 1 }
  }
})
export const { increment, decrement } = counterSlice.actions
export default configureStore({ reducer: { counter: counterSlice.reducer } })

9. 非同期処理とRedux Thunk

API通信など非同期処理にはRedux Thunkがよく使われます。ThunkはAction Creatorが関数を返すことで、dispatchのタイミングや複数回のdispatchを制御できます。

import thunk from 'redux-thunk'
import { createStore, applyMiddleware } from 'redux'
const store = createStore(reducer, applyMiddleware(thunk))
function fetchData() {
  return async dispatch => {
    dispatch({ type: 'FETCH_START' })
    const res = await fetch('/api/data')
    const data = await res.json()
    dispatch({ type: 'FETCH_SUCCESS', payload: data })
  }
}
store.dispatch(fetchData())

10. Middlewareの活用

ReduxのMiddlewareは、ActionとReducerの間に独自の処理を挟む仕組みです。ロギング、非同期処理、エラー監視など様々な拡張が可能です。

const logger = store => next => action => {
  console.log('dispatching', action)
  let result = next(action)
  console.log('next state', store.getState())
  return result
}
const store = Redux.createStore(reducer, Redux.applyMiddleware(logger))

11. 状態の永続化とlocalStorage連携

Reduxの状態をlocalStorageなどに保存することで、ページリロード後も状態を維持できます。subscribeで状態変更時に保存し、初期値として読み込むことで実現します。

const persistedState = JSON.parse(localStorage.getItem('state')) || undefined
const store = Redux.createStore(reducer, persistedState)
store.subscribe(() => {
  localStorage.setItem('state', JSON.stringify(store.getState()))
})

12. Redux DevToolsによるデバッグ

Redux DevToolsは、状態の変化やActionの履歴を可視化できる強力なデバッグツールです。開発時にストア作成時に組み込むだけで利用できます。

const store = Redux.createStore(
  reducer,
  window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
)

13. 実践:TODOアプリのRedux実装例

Reduxの実力を体感するには、TODOアプリのような複数データの管理が最適です。タスク追加・完了切り替えなどをReducerとActionで管理し、状態の一元化とデータフローの明確化を実感できます。

// reducer.js
const initialState = { tasks: [] }
function todoReducer(state = initialState, action) {
  switch (action.type) {
    case 'ADD_TASK':
      return { ...state, tasks: [...state.tasks, { text: action.text, done: false }] }
    case 'TOGGLE_TASK':
      return {
        ...state,
        tasks: state.tasks.map((t, i) =>
          i === action.index ? { ...t, done: !t.done } : t
        )
      }
    default:
      return state
  }
}
export default todoReducer

14. Reduxのメリットと注意点

Reduxは状態管理を一元化し、予測可能で安定したアプリケーションを実現します。大規模開発や複雑なデータフローのあるアプリで特に威力を発揮しますが、小規模アプリでは導入コストが高くなる場合もあるため、プロジェクト規模に応じて選択しましょう。

15. まとめと今後の展望

ReduxはJavaScriptフロントエンド開発における状態管理のデファクトスタンダードです。Reactとの組み合わせはもちろん、Redux ToolkitやMiddleware、DevToolsなどのエコシステムも充実しています。今後も進化が期待されるReduxを、ぜひあなたのプロジェクトでも活用してみてください。

0
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
0
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?