React Hooks のカスタムフックパターンについて、API の呼び出しレベルにとどまっている開発者は多い。本記事では本番環境の観点から、実際に遭遇する問題とその解決策を論じる。
基本原理
これをベースにさらに最適化できる:
javascript
import { useReducer, useCallback } from 'react'
const initialState = { items: [], filter: '', sort: 'date' }
function reducer(state, action) {
switch (action.type) {
case 'SET_ITEMS': return { ...state, items: action.payload }
case 'SET_FILTER': return { ...state, filter: action.payload }
case 'ADD_ITEM': return { ...state, items: [...state.items, action.payload] }
case 'REMOVE_ITEM': return { ...state, items: state.items.filter(i => i.id !== action.payload) }
default: throw new Error(`Unknown: ${action.type}`)
}
}
このパターンは大規模プロジェクトで非常に実用的で、保守コストを大幅に下げられる。
高度な機能
実際のプロジェクトではもう少し複雑に使うことになる:
javascript
import { useReducer, useCallback } from 'react'
const initialState = { items: [], filter: '', sort: 'date' }
function reducer(state, action) {
switch (action.type) {
case 'SET_ITEMS': return { ...state, items: action.payload }
case 'SET_FILTER': return { ...state, filter: action.payload }
case 'ADD_ITEM': return { ...state, items: [...state.items, action.payload] }
case 'REMOVE_ITEM': return { ...state, items: state.items.filter(i => i.id !== action.payload) }
default: throw new Error(`Unknown: ${action.type}`)
}
}
この方法で、コードのテスト容易性と拡張性の両方が向上する。
プロジェクト実践
以下は完全なサンプルである:
javascript
import { useReducer, useCallback } from 'react'
const initialState = { items: [], filter: '', sort: 'date' }
function reducer(state, action) {
switch (action.type) {
case 'SET_ITEMS': return { ...state, items: action.payload }
case 'SET_FILTER': return { ...state, filter: action.payload }
case 'ADD_ITEM': return { ...state, items: [...state.items, action.payload] }
case 'REMOVE_ITEM': return { ...state, items: state.items.filter(i => i.id !== action.payload) }
default: throw new Error(`Unknown: ${action.type}`)
}
}
境界条件の処理に注意。本番環境では極めて重要だ。
ベストプラクティス
重要なのはコアロジックを理解することだ:
javascript
import { useReducer, useCallback } from 'react'
const initialState = { items: [], filter: '', sort: 'date' }
function reducer(state, action) {
switch (action.type) {
case 'SET_ITEMS': return { ...state, items: action.payload }
case 'SET_FILTER': return { ...state, filter: action.payload }
case 'ADD_ITEM': return { ...state, items: [...state.items, action.payload] }
case 'REMOVE_ITEM': return { ...state, items: state.items.filter(i => i.id !== action.payload) }
default: throw new Error(`Unknown: ${action.type}`)
}
}
パフォーマンス最適化は具体的な場面と組み合わせる必要があり、あらゆるケースで過度な最適化が必要なわけではない。
ハマりやすい注意点
以下のようなアプローチで改善できる:
javascript
import { useReducer, useCallback } from 'react'
const initialState = { items: [], filter: '', sort: 'date' }
function reducer(state, action) {
switch (action.type) {
case 'SET_ITEMS': return { ...state, items: action.payload }
case 'SET_FILTER': return { ...state, filter: action.payload }
case 'ADD_ITEM': return { ...state, items: [...state.items, action.payload] }
case 'REMOVE_ITEM': return { ...state, items: state.items.filter(i => i.id !== action.payload) }
default: throw new Error(`Unknown: ${action.type}`)
}
}
このアプローチは本番環境で半年以上安定稼働しており、実際に検証済みだ。
まとめ
- 新しい技術のために新しい技術を使ってはいけない
- コード例は参考程度。業務のシナリオに合わせて調整が必要
- カスタムフックパターンは万能薬ではなく、プロジェクトの規模や技術スタックに応じて選ぶ必要がある
- API を暗記するより、裏側の原理を理解する方が重要
